DEV Community

Cover image for Hydrated Bloc: Persist your App State.
Md. Mobin
Md. Mobin

Posted on

Hydrated Bloc: Persist your App State.

Quench your app's thirst with the magic of Flutter and the power of "Hydrated Bloc" - the ultimate elixir to keep your application state hydrated and happy! 🧊💧

"Hydrated Bloc" simplifies state persistence in Flutter, making it effortless to store and restore your app's state. Say goodbye to manual state serialization and deserialization – this nifty extension takes care of it all! With Hydrated Bloc, you can focus on crafting your app's features and delighting your users without worrying about state management complexities.

What is Hydrated Bloc and How Does it Work?

Hydrated Bloc is a powerful extension built on top of the bloc package in Flutter. It automates the process of state persistence and restoration, making it easy to maintain your app's state across different sessions. When you create a BlocProvider, Hydrated Bloc automatically leverages the fromJson method to retrieve the stored state from the local storage.

Whenever the bloc's state changes, the toJson method comes into play. It converts the current state into a Map<String, dynamic> format, which is then stored in the local storage. This ensures that your app's state is always up-to-date and ready to be restored when needed, even if the app is closed or the user navigates between screens.

Hydrated Bloc streamlines the process of state persistence, preventing the hassle of handling manual serialization and deserialization. By automating state management, it enhances your app's reliability and eliminates the risk of state loss.

Benefits of Hydrated Bloc Over Traditional Bloc

Hydrated Bloc Bloc
State Persistence Automates state persistence and restoration. Manual state serialization and deserialization.
Package Dependency Built as an extension to package:bloc. Directly uses package:bloc.
Complexity Simplifies state management with automatic persistence. Requires additional handling for state persistence.
Initialization HydratedBloc initializes from stored state if available. Bloc starts with initial state on each launch.
Storage Utilizes local storage(hive[No SQL]) to persist the states. No built-in state storage, left to developers.
App Reliability Enhances app reliability by preventing state loss. Prone to state loss if not handled properly.

Getting Started with Hydrated Bloc

Using Hydrated Bloc is a breeze! You have two options to get started:

  • By Extending: You can use Hydrated Bloc by extending the existing bloc class.
sealed class CounterEvent {}
final class CounterIncrementPressed extends CounterEvent {}

class CounterBloc extends HydratedBloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
  }

  @override
  int fromJson(Map<String, dynamic> json) => json['value'] as int;

  @override
  Map<String, int> toJson(int state) => { 'value': state };
}

Enter fullscreen mode Exit fullscreen mode
  • Using HydratedMixin:
class CounterBloc extends Bloc<CounterEvent, int> with HydratedMixin {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
  }

  @override
  int fromJson(Map<String, dynamic> json) => json['value'] as int;

  @override
  Map<String, int> toJson(int state) => { 'value': state };
}

Enter fullscreen mode Exit fullscreen mode

To access and manipulate the storage object in Hydrated Bloc, follow these steps:

  • Create a custom storage class by extending the Storage class.
class MyHydratedStorage implements Storage {
  @override
  dynamic read(String key) {
    // TODO: implement read
  }

  @override
  Future<void> write(String key, dynamic value) async {
    // TODO: implement write
  }

  @override
  Future<void> delete(String key) async {
    // TODO: implement delete
  }

  @override
  Future<void> clear() async {
    // TODO: implement clear
  }
}

Enter fullscreen mode Exit fullscreen mode
  • Set the custom storage implementation:
HydratedBloc.storage = MyHydratedStorage();
Enter fullscreen mode Exit fullscreen mode

Inside the custom storage class, you can implement methods to read, write, delete, and clear data. These methods allow you to interact with the local storage and manage data for the Hydrated Bloc.

Let's Create a Simple To-Do Application

  • Create a Flutter project and add the required dependencies to your pubspec.yaml file.
dependencies:
  hydrated_bloc: ^9.1.2  //hydrated bloc
  path_provider: ^2.0.15  // for getTemporaryDirectory
  flutter_easyloading: ^3.0.5 // Helpful for showing loading without context
  flutter_bloc: ^8.1.3 //flutter bloc
Enter fullscreen mode Exit fullscreen mode

for more information hydrated_bloc

  • Define the To-Do model for JSON serialization.
  • Create the Todo repository to manage tasks.
  • Define the possible states and events for the Todo Bloc.
  • Implement the Todo Bloc with Hydrated Bloc.
  • Initialize the Hydrated Bloc storage in main.dart.
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  HydratedBloc.storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorage.webStorageDirectory
        : await getTemporaryDirectory(),
  );
  runApp(const MyApp());
}
Enter fullscreen mode Exit fullscreen mode
  • Now we are remaining with UI and widgets for that you can create own or refer to github-repo.

Various function to manipulate Todo List

  • Adding New Todo:

 if (formKey.currentState!.validate()) {
BlocProvider.of<TodoBloc>(context).add(TodoAdd(TodoModel.fromJson({
                        'id': DateTime.now().millisecondsSinceEpoch+
                            Random().nextInt(9999999),
                        'title': titleText.text,
                        'description': description.text,
                        'is_completed': false,
                        'created_at': DateTime.now().toUtc().toIso8601String(),
                        'updated_at': DateTime.now().toUtc().toIso8601String()
                      })));
     Navigator.pop(context);
                    }
Enter fullscreen mode Exit fullscreen mode
  • Update ToDo:
BlocProvider.of<TodoBloc>(context).add(TodoUpdate(task.id, value!));

Enter fullscreen mode Exit fullscreen mode
  • Remove ToDo:
BlocProvider.of<TodoBloc>(context).add(TodoRemove(task.id));
Enter fullscreen mode Exit fullscreen mode

OUTPUT

Certainly! My gratitude goes out to the amazing authors and contributors of the hydrated_bloc package, including Felix Angelovand others, for their brilliant work in developing this powerful tool for state management in Flutter.

Source code :

Github Repo

Follow me on

Top comments (1)

Collapse
 
blazlew profile image
Błażej Lewandowski

neat!