bloc_signals_hydrate 0.1.2
bloc_signals_hydrate: ^0.1.2 copied to clipboard
State persistence and hydration adapters for BlocSignal state containers.
β‘ bloc_signals_hydrate #
"With the rigor of Bloc and the flex and speed of Signal"
State persistence and hydration adapters for BlocSignal state containers.
HydratedCubitSignal and HydratedBlocSignal automatically persist state changes to storage and restore state synchronously during container instantiation across app restarts.
π Ecosystem Packages #
| Package | Purpose | Pub.dev Link |
|---|---|---|
bloc_signals |
Core pure-Dart state containers, event registry, & VM Service telemetry | π¦ pub.dev |
bloc_signals_flutter |
Flutter UI widgets (BlocSignalProvider, BlocSignalBuilder, BlocSignalListener, BlocSignalConsumer, BlocSignalSelector) |
π¦ pub.dev |
bloc_signals_riverpod |
Bidirectional Riverpod interop adapters (toBlocSignal(ref), toProvider()) |
π¦ pub.dev |
bloc_signals_hydrate |
Persistent state storage (HydratedCubitSignal, HydratedBlocSignal) |
π¦ pub.dev |
bloc_signals_devtools |
Dedicated Flutter DevTools extension inspector UI | π¦ pub.dev |
bloc_signals_test |
Declarative unit testing helpers (blocSignalTest) |
π¦ pub.dev |
bloc_signals_lint |
Static analysis lints & IDE quick-fixes | π¦ pub.dev |
otel_bloc_signals |
OpenTelemetry tracing observers | π¦ pub.dev |
β‘ Key Features #
- π¦
dynamic/Object?JSON Support:fromJson(dynamic json)andtoJson(StateType state)accept primitives (num,String,bool,List,Map). Primitive states do not require map wrappers like{"value": 42}! - β‘ Synchronous Initial Hydration: State is restored synchronously during constructor executionβmeaning initial widget builds render hydrated data immediately with zero frame flicker.
- π οΈ Zero-Dependency Default: Ships with
MemoryHydratedStoragefor fast in-memory unit testing out-of-the-box.
π Getting Started #
Add bloc_signals_hydrate to your pubspec.yaml:
dependencies:
bloc_signals: ^0.2.5
bloc_signals_hydrate: ^0.1.1
π‘ Quick Examples #
1. Primitive State Hydration (HydratedCubitSignal) #
import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';
class CounterCubit extends HydratedCubitSignal<int> {
CounterCubit() : super(initialState: 0);
void increment() => emit(stateValue + 1);
@override
int? fromJson(dynamic json) => json as int?;
@override
dynamic toJson(int state) => state; // Return primitive directly!
}
2. Complex Object Hydration (HydratedBlocSignal) #
import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';
class UserCubit extends HydratedCubitSignal<UserModel> {
UserCubit() : super(initialState: UserModel.anonymous);
@override
UserModel? fromJson(dynamic json) {
if (json is Map<String, dynamic>) {
return UserModel.fromJson(json);
}
return null;
}
@override
dynamic toJson(UserModel state) => state.toJson();
}
3. Wiring Custom Storage (SharedPreferences) #
import 'dart:convert';
import 'package:bloc_signals_hydrate/bloc_signals_hydrate.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SharedPreferencesHydratedStorage implements HydratedStorage {
SharedPreferencesHydratedStorage(this.prefs);
final SharedPreferences prefs;
@override
dynamic read(String key) {
final value = prefs.getString(key);
return value != null ? jsonDecode(value) : null;
}
@override
Future<void> write(String key, dynamic value) async =>
prefs.setString(key, jsonEncode(value));
@override
Future<void> delete(String key) async => prefs.remove(key);
@override
Future<void> clear() async => prefs.clear();
}
void main() async {
final prefs = await SharedPreferences.getInstance();
HydratedStorage.storage = SharedPreferencesHydratedStorage(prefs);
}
π License #
MIT License. See LICENSE for details.