Skip to content

State management

As explained in Flutter docs, consider state as “whatever data you need in order to rebuild your UI at any moment in time”. State management refers to the way you manage the state of your application. It is required to share data across different parts of the app. In Flutter, state management is crucial because it helps you manage the state of your widgets and ensures that your UI updates in response to state changes.

Flutter builds its user interface to reflect the current state of your app: State management

Provider Package

The Provider package is a popular state management solution in Flutter. It allows you to manage and propagate state across your application efficiently. It uses the ChangeNotifier class to notify listeners about state changes, which then rebuilds the UI accordingly.

How it works?

  1. Data Model: The data model represents the state that you want to manage and share across your application. It contains the data and logic to update the state.
  2. ChangeNotifier Class: The ChangeNotifier class is a part of the Flutter framework that provides a simple way to manage state. It provides the ability to notify listeners about state changes.
  3. Notify Listeners: When the state changes, the ChangeNotifier class calls the notifyListeners() method to notify all registered listeners. This triggers a rebuild of the UI components that are listening to the state.
  4. Consumer: The Consumer widget listens to changes in the state and rebuilds the UI accordingly. It helps to optimize the performance by rebuilding only the specific parts of the UI that depend on the state.
  5. ChangeNotifierProvider: The ChangeNotifierProvider widget provides an instance of the ChangeNotifier class to the widget tree, making it available to all descendant widgets.

Usage

We use provider in the starter kit to manage the state of the app.

  • ThemeProvider: Manages the theme state, allowing toggling between light and dark modes
  • CartProvider: Manages the state of the shopping cart
  • UserAuthProvider: Manages the authentication state

Code up

  1. Add provider dependency to pubspec.yaml

  2. Create a class/object to represent the state. Examples:

    • ThemeData contains the theme data (light or dark).
    • CartItem contains the cart item data (product, quantity and method to update the quantity).
    • Auth contains the authentication data of the user. This is already defined by firebase_auth package.
  3. Create provider class that extends ChangeNotifier class. It extends ChangeNotifier to provide the ability to notify listeners about state changes.

    • ThemeProvider class manages the theme state (ThemeData)
    • CartProvider class manages the shopping cart state (Map<String, CartItem> _itemsMap)
    • UserAuthProvider class manages the authentication state (Auth) by using AuthService to get the current user’s authentication state.
  4. Create a ChangeNotifierProvider widget:

    ChangeNotifierProvider(
    create: (context) => ThemeProvider(),
    child: child,
    )

    If you want to use multiple providers, you can use MultiProvider widget.

    runApp(MultiProvider(
    providers: [
    ChangeNotifierProvider(create: (context) => ThemeProvider()),
    ChangeNotifierProvider(create: (context) => UserAuthProvider()),
    ChangeNotifierProvider(create: (context) => CartProvider()),
    ],
    child: const MyApp())
    );
  5. Use a Consumer widget to build the UI:

    • Wrap the part of the widget tree that depends on the state with a Consumer widget.
    • The Consumer widget takes a builder function that provides the current state and allows you to build the UI based on that state.
    Consumer<ThemeProvider>(
    builder: (context, themeProvider, child) {
    return MaterialApp(
    theme: themeProvider.getTheme(),
    home: HomeScreen(),
    );
    },
    );
    • In this example, the Consumer widget listens to changes in the ThemeProvider and rebuilds the MaterialApp with the updated theme.
  6. Alternatively, use Provider.of to access the state:

    • You can use Provider.of<ThemeProvider>(context).themeData to access the state directly without wrapping the widget tree with a Consumer widget.
    • This approach is useful when you need to access the state in a less reactive manner, such as in event handlers or one-time state access.
    final themeData = Provider.of<ThemeProvider>(context).themeData;
    return MaterialApp(
    theme: themeData,
    home: HomeScreen(),
    );
    • In this example, Provider.of is used to get the themeData directly from the ThemeProvider without rebuilding the widget tree when the state changes.
    • Unlike Consumer, Provider.of does not automatically rebuild the UI when the state changes. It is more suitable for scenarios where you do not need continuous updates.

Summary

  1. State Management: Managing the state of your application to ensure the UI updates in response to state changes.
  2. Provider Package: A popular state management solution in Flutter using ChangeNotifier to notify listeners about state changes.
  3. ThemeProvider: Manages the theme state, allowing toggling between light and dark modes.
  4. CartProvider: Manages the state of the shopping cart.
  5. AuthProvider: Manages the authentication state

Reference

  1. https://docs.flutter.dev/data-and-backend/state-mgmt/intro