
Where Flutter State Meets Simplicity
A thoughtfully designed state management solution for Flutter developers who value clarity, performance, and maintainable code architecture.
Be an early adopter! Join our growing community and help shape the future of Flutter state management.
Simple, Elegant API
ZenState's clean API makes state management straightforward while giving you powerful tools when you need them.
1// Simple state with Atoms
2final counterAtom = Atom<int>(0);
3
4// Update state with a clean API
5void increment() => counterAtom.value++;
6
7// Use in widgets with minimal boilerplate
8class CounterWidget extends StatelessWidget {
9
10 Widget build(BuildContext context) {
11 // Watch the atom and rebuild when it changes
12 final count = counterAtom.watch(context);
13
14 return Column(
15 children: [
16 Text('Count: $count', style: Theme.of(context).textTheme.headline4),
17 ElevatedButton(
18 onPressed: increment,
19 child: Text('Increment'),
20 ),
21 ],
22 );
23 }
24}
Powerful Features, Elegant Design
ZenState combines simplicity with advanced capabilities to give you complete control over your app's state.
Reactive Atoms
Granular state units that automatically track dependencies and optimize UI updates.
Command Pattern
Encapsulate state changes in explicit, testable command objects for better organization.
Computed State
Derived values that automatically update when their dependencies change.
Async Support
First-class support for async operations with loading and error states.
Persistence
Easily save and restore state with built-in persistence adapters.
Developer Tools
Time-travel debugging and state inspection for a better development experience.
How ZenState Works
A clean architecture that makes state management intuitive and maintainable.
1// 1. Define your feature module
2class TodoFeature extends ZenFeature {
3
4 String get name => 'todos';
5
6 // State containers
7 late final todosAtom = registerAtom('items', <Todo>[]);
8
9 // Derived state (computed automatically)
10 late final completedCountDerived = registerDerived(
11 'completedCount',
12 () => todosAtom.value.where((todo) => todo.completed).length
13 );
14
15 // Commands for operations
16 late final toggleTodoCommand = registerFunctionCommand<String, void>(
17 'toggleTodo',
18 (id) {
19 todosAtom.update((todos) => todos.map((todo) =>
20 todo.id == id ? todo.copyWith(completed: !todo.completed) : todo
21 ).toList());
22 },
23 );
24}
25
26// 2. Use the feature in your widgets
27Widget buildTodoList(BuildContext context) {
28 // Access the feature
29 final todoFeature = context.feature<TodoFeature>();
30
31 // Watch state changes
32 final todos = todoFeature.todosAtom.watch(context);
33 final completedCount = todoFeature.completedCountDerived.watch(context);
34
35 return Column(
36 children: [
37 Text('Completed: $completedCount / ${todos.length}'),
38 Expanded(
39 child: ListView.builder(
40 itemCount: todos.length,
41 itemBuilder: (context, index) => CheckboxListTile(
42 title: Text(todos[index].title),
43 value: todos[index].completed,
44 onChanged: (_) => todoFeature.toggleTodoCommand.execute(todos[index].id),
45 ),
46 ),
47 ),
48 ],
49 );
50}
Atomic State
Break your state into small, focused atoms that are easy to reason about and test.
Command Pattern
Encapsulate state changes in explicit commands for better organization and testability.
Reactive UI
UI components automatically update when their state dependencies change, with minimal rebuilds.
Composable Architecture
Compose complex state from simple building blocks, creating a scalable architecture.
Advanced Use Cases
ZenState scales elegantly from simple counter apps to complex enterprise applications.
1// Smart optimization with context awareness
2class SearchFeature extends ZenFeature {
3
4 String get name => 'search';
5
6 // Query with debouncing and context awareness
7 late final queryAtom = registerSmartAtom(
8 'query',
9 '',
10 // Debounce rapid typing
11 optimizer: DebouncingOptimizer<String>(
12 duration: Duration(milliseconds: 300),
13 ),
14 // Adapt based on device conditions
15 contextFactors: [BatteryFactor(), NetworkFactor()],
16 );
17
18 // Search results with loading state
19 late final resultsAtom = registerAtom('results', <SearchResult>[]);
20 late final searchFuture = registerFuture<List<SearchResult>>('search');
21
22 // Perform search when query changes
23 SearchFeature() {
24 // Listen to query changes
25 queryAtom.addListener(_onQueryChanged);
26 }
27
28 void _onQueryChanged() {
29 if (queryAtom.value.isEmpty) {
30 resultsAtom.value = [];
31 return;
32 }
33
34 // Use the correct load method from ZenFuture
35 searchFuture.load(() async {
36 final results = await searchService.search(queryAtom.value);
37 resultsAtom.value = results;
38 return results;
39 });
40 }
41
42
43 void dispose() {
44 queryAtom.removeListener(_onQueryChanged);
45 super.dispose();
46 }
47}
48
49// Usage in a widget
50class SearchScreen extends StatelessWidget {
51
52 Widget build(BuildContext context) {
53 final searchFeature = context.feature<SearchFeature>();
54 final query = searchFeature.queryAtom.watch(context);
55 final results = searchFeature.resultsAtom.watch(context);
56 final isLoading = searchFeature.searchFuture.isLoading;
57
58 return Column(
59 children: [
60 TextField(
61 onChanged: (value) => searchFeature.queryAtom.value = value,
62 decoration: InputDecoration(
63 hintText: 'Search...',
64 suffixIcon: isLoading ? CircularProgressIndicator() : null,
65 ),
66 ),
67 Expanded(
68 child: searchFeature.searchFuture.when(
69 initial: () => Center(child: Text('Enter a search term')),
70 loading: () => Center(child: CircularProgressIndicator()),
71 success: (data) => ListView.builder(
72 itemCount: results.length,
73 itemBuilder: (context, index) => ListTile(
74 title: Text(results[index].title),
75 ),
76 ),
77 error: (error, stackTrace) => Center(
78 child: Text('Error: ${error.toString()}'),
79 ),
80 ),
81 ),
82 ],
83 );
84 }
85}
Reactive by Design
ZenState automatically tracks dependencies between state atoms and derived values, ensuring your UI updates efficiently when data changes.
Explicit State Changes
Commands encapsulate state mutations, making your code more maintainable and easier to test. Each state change is explicit and traceable.
Ready to simplify your state management?
Start building more maintainable Flutter applications today with ZenState's elegant and powerful approach.
ZenState is a new library looking for early adopters and contributors
Join our community