syncx 0.0.4
syncx: ^0.0.4 copied to clipboard
A lightweight, flexible state management solution for Flutter, providing notifiers, builders, and consumers for reactive UI updates with minimal boilerplate.
SyncX #
A lightweight, flexible state management solution for Flutter, providing notifiers, builders, and consumers for reactive UI updates with minimal boilerplate. SyncX is inspired by simplicity and composability, making it easy to manage state in your Flutter apps.
Note: The implementation and API of SyncX are inspired by popular state management solutions such as bloc, provider, and riverpod. Naming conventions and patterns are chosen to be developer-friendly, especially for those migrating from or familiar with these libraries.
Features #
- π Notifier-based state management: Simple, extendable notifiers for your app's state.
- ποΈ Builder widgets: Easily rebuild UI in response to state changes.
- π Listener widgets: React to state changes with side effects.
- πͺΆ Minimal boilerplate: Focus on your app logic, not on wiring up state.
- β‘ Async state support: Built-in support for loading, data, and error states in async flows.
Getting Started #
Add SyncX to your pubspec.yaml:
dependencies:
syncx: ^0.0.3
Then run:
flutter pub get
Core Concepts & Usage #
1. Create a Notifier #
A Notifier holds and updates your state:
class CounterNotifier extends Notifier<int> {
CounterNotifier() : super(0);
void increment() => setState(state + 1);
}
For async state (loading/data/error):
class GreetingAsyncNotifier extends AsyncNotifier<String> {
GreetingAsyncNotifier() : super();
@override
Future<AsyncState<String>> onInit() async {
// Consider this as a Network call
await Future.delayed(const Duration(seconds: 2));
if (success...) {
return const AsyncState.data('Hello from AsyncNotifier!');
}
return const AsyncState.error(ErrorState('Failed to load greeting'));
}
}
2. Register the Notifier #
Register your notifier at the root of your widget tree:
NotifierRegister<CounterNotifier, int>(
create: (_) => CounterNotifier(),
child: MyApp(),
)
You can nest registers for multiple notifiers:
NotifierRegister<CounterNotifier, int>(
create: (_) => CounterNotifier(),
child: NotifierRegister<GreetingAsyncNotifier, AsyncState<String>>(
create: (_) => GreetingAsyncNotifier(),
child: MyApp(),
),
)
3. Consume State with Builders & Listeners #
Rebuild UI on State Change:
NotifierBuilder<CounterNotifier, int>(
builder: (context, count) => Text('Count: $count'),
)
Control rebuilds:
NotifierBuilder<CounterNotifier, int>(
buildWhen: (prev, curr) => prev != curr,
builder: (context, count) => Text('Count: $count'),
)
Listen for Side Effects:
NotifierListener<CounterNotifier, int>(
listenWhen: (prev, curr) => curr % 2 == 0,
listener: (count) => print('Count is even: $count'),
child: MyWidget(),
)
Combine Build and Listen:
NotifierConsumer<CounterNotifier, int>(
builder: (context, count) => Text('Count: $count'),
listener: (count) => print('Count changed: $count'),
)
Async State Handling:
NotifierBuilder<GreetingAsyncNotifier, AsyncState<String>>(
builder: (context, state) => state.when(
loading: () => CircularProgressIndicator(),
data: (greeting) => Text(greeting),
error: (e) => Text('Error: ${e.message ?? e.error}'),
),
)
Usage Patterns #
- Rebuild UI on State Change: Use
NotifierBuilderwithbuildWhenfor fine-grained rebuild control. - Listen for Side Effects: Use
NotifierListenerwithlistenWhenfor side-effect logic. - Combine Build and Listen: Use
NotifierConsumerfor both UI and side effects. - Async State Handling: Use
AsyncNotifierandAsyncStatefor loading, data, and error flows.
Future Plans #
- Built-in stream support in notifiers for easy loading and error state management.
- Top-level observer support to monitor state changes across the app.
- Migrate dependency injection (DI) from provider to a custom DI implementation for more flexibility and control.
Contributing #
Contributions are welcome! Please open issues or pull requests on GitHub.
License #
This project is licensed under the MIT License.
If you have questions or need help, please open an issue or start a discussion on GitHub.