Shard
A powerful, lightweight state management solution for Flutter. Built-in persistence, async support, debounce & throttle, and a service locator—all in one package, no heavy frameworks.
Quick Start
1. Add to pubspec.yaml
dependencies:
shard: ^1.0.0
2. Create a Shard
import 'package:shard/shard.dart';
class CounterShard extends Shard<int> {
CounterShard() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
3. Provide and Use
// Wrap your app
ShardProvider<CounterShard>(
create: () => CounterShard(),
child: MaterialApp(
home: CounterScreen(),
),
)
// In your widget
ShardBuilder<CounterShard, int>(
builder: (context, count) => Text('Count: $count'),
)
// In callbacks
ElevatedButton(
onPressed: () => context.read<CounterShard>().increment(),
child: Text('+'),
)
That's it! You're ready to go.
What is Shard?
Shard is a state management solution built on Flutter's ChangeNotifier. It provides:
- Simple API —
emit()to update state,onChange()for lifecycle hooks - Type-safe — Full Dart type safety, no code generation
- Persistence — Automatic state persistence with
PersistentShard - Async support —
FutureShardandStreamShardfor async operations - Performance — Built-in debounce, throttle, and response caching
- Widgets —
ShardBuilder,ShardSelector,AsyncShardBuilder - Service locator —
ShardLocatorfor singletons (no GetIt needed)
Why Shard?
- Zero boilerplate — Simple API, less code
- Built-in features — Persistence, caching, debounce/throttle included
- Type-safe — Full Dart type system, no code generation
- Lightweight — Minimal dependencies, no heavy frameworks
- Testable — Clear separation of concerns
- Production-ready — Stable API (1.0.0)
Key Features
| Feature | Description |
|---|---|
| Shard | Base state management with emit(), lifecycle hooks |
| FutureShard | Async state from Future with automatic caching |
| StreamShard | Async state from Stream for real-time data |
| PersistentShard | Automatic state persistence across app restarts |
| ShardBuilder | Widget that rebuilds on state changes |
| ShardSelector | Optimized widget that rebuilds only when selected value changes |
| AsyncShardBuilder | Widget for async states (loading/data/error) |
| DebounceMixin | Delay execution until inactivity period |
| ThrottleMixin | Limit execution to once per time period |
| ShardLocator | Simple service locator for singletons |
Examples
Async State with FutureShard
class UserShard extends FutureShard<User> {
final String userId;
UserShard({required this.userId});
@override
Future<User> build() => api.getUser(userId);
@override
bool get allowCache => true; // Enable caching
}
// In UI
AsyncShardBuilder<UserShard, User>(
onLoading: (context) => CircularProgressIndicator(),
onData: (context, user) => Text('Hello, ${user.name}'),
onError: (context, error, _) => Text('Error: $error'),
)
Persistence
class CounterShard extends SimplePersistentShard<int> {
CounterShard() : super(
0,
storageFactory: () => SharedPreferencesStorage.getInstance(),
serializer: IntSerializer(),
);
@override
String get persistenceKey => 'counter';
void increment() => emit(state + 1);
}
Debounce & Throttle
class SearchShard extends Shard<SearchState> {
void updateQuery(String query) {
emit(state.copyWith(query: query));
// Debounce search API call
debounce('search', () => performSearch(query),
duration: Duration(milliseconds: 500));
}
}
class ScrollShard extends Shard<ScrollState> {
void onScroll() {
// Throttle load-more to once per second
throttle('loadMore', () => loadMore(),
duration: Duration(seconds: 1));
}
}
Service Locator
void main() {
// Register singletons
ShardLocator.registerSingleton<ApiClient>(ApiClient());
ShardLocator.registerLazySingleton<Repository>(
() => Repository(ShardLocator.get<ApiClient>()),
);
runApp(MyApp());
}
// Use anywhere
final repo = ShardLocator.get<Repository>();
Documentation
License
See LICENSE file for details.
Libraries
- Shard - A powerful, lightweight state management solution for Flutter.