statecraft
π― Elegant, lightweight state handling for Flutter and flutter_bloc.
statecraft
provides simple yet powerful state models (AsyncState<T>
) that you can use in your Flutter apps, especially with flutter_bloc
, Cubit
, or any state management solution.
It removes boilerplate and helps you manage async operations (loading, success, failure) cleanly.
π Features
- Typed
AsyncState<T>
sealed classes - Built-in
when
,maybeWhen
, andwhenOrNull
APIs - Designed for Dart 3 (
sealed
,final
classes) - Extremely lightweight (no code generation, no dependencies)
- Perfect companion for
flutter_bloc
andCubit
- Fully extensible β Form, List, and Pagination states coming soon!
π¦ Installation
dart pub add statecraft
or manually in your pubspec.yaml
:
dependencies:
statecraft: ^0.1.0
β¨ Philosophy
Handling asynchronous states in Flutter is a repetitive task.
Typically you create:
- Loading State
- Success State
- Error State
for every BLoC manually.
This leads to boilerplate and messy switch-cases.
statecraft
solves this by providing one unified AsyncState you can reuse everywhere.
π§© Usage with flutter_bloc
Hereβs a complete real-world example:
1. Define your Cubit
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:statecraft/statecraft.dart';
class PostCubit extends Cubit<AsyncState<Post>> {
final PostRepository repository;
PostCubit(this.repository) : super(const AsyncInitial());
Future<void> fetchPost(int id) async {
emit(const AsyncLoading());
try {
final post = await repository.getPost(id);
emit(AsyncSuccess(post));
} catch (e) {
emit(AsyncFailure(e.toString()));
}
}
}
2. Use it in your Flutter Widget
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:statecraft/statecraft.dart';
class PostScreen extends StatelessWidget {
const PostScreen({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => PostCubit(PostRepository()),
child: Scaffold(
appBar: AppBar(title: const Text('Post')),
body: BlocBuilder<PostCubit, AsyncState<Post>>(
builder: (context, state) {
return state.when(
initial: () => const Center(child: Text('Press the button to load post')),
loading: () => const Center(child: CircularProgressIndicator()),
success: (post) => Center(child: Text('Post title: ${post.title}')),
failure: (error) => Center(child: Text('Failed: $error')),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.read<PostCubit>().fetchPost(1),
child: const Icon(Icons.download),
),
),
);
}
}
β¨ AsyncState Lifecycle
State | Meaning |
---|---|
AsyncInitial |
The initial idle state before anything starts |
AsyncLoading |
Represents an ongoing async operation |
AsyncSuccess<T> |
Represents a successful operation with T data |
AsyncFailure |
Represents a failure with an error message |
π API Overview
All AsyncState
when
β handle every case explicitlymaybeWhen
β handle some cases, fallback withorElse
whenOrNull
β handle only what you need, ignore others
Example:
state.maybeWhen(
success: (data) => Text('Data loaded: $data'),
orElse: () => const CircularProgressIndicator(),
);
π§ Roadmap
x
AsyncState<T>
(this release!)FormState<T>
β for form submissionsListState<T>
β for simple list loadingPaginationState<T>
β for infinite scroll and pagination
π License
This package is licensed under the MIT License.
Feel free to use it in your personal or commercial projects.
π Why use statecraft?
- Stop writing Loading/Loaded/Error states manually.
- Make your Flutter BLoCs smaller, readable, and powerful.
- Type-safe state management with zero extra dependencies.
- Grow with your app: Forms, Lists, Pagination coming soon!
Made with β€οΈ for Flutter devs who love clean architecture.
Libraries
- statecraft
- Support for doing something awesome.