# How to Use Provider for State Management in Flutter || Part - 1

**Provider** is one of the recommended state management options when using Flutter. It simplifies data flow within your app, making it more manageable and scalable. Here’s a brief overview:

1. **What is Provider?**
    
    * Provider is a package in Flutter that allows you to manage application state efficiently.
        
    * It follows the provider design pattern, enabling components to consume data without needing to know the source of that data.
        
    * This decoupling makes it easier to refactor, test, and maintain your code.
        
2. **How does it work?**
    
    * When you place a `Provider` widget in your widget tree, all its children have access to the values exposed by it.
        
    * There are different types of providers, but for this explanation, let’s focus on `ChangeNotifierProvider`.
        
    * `ChangeNotifierProvider` allows you to listen to changes in the provider and automatically rebuilds widgets when needed.
        
    * You can create your own custom providers by extending `ChangeNotifier` you can create your own custom providers by extending `ChangeNotifier` or other provider classes.
        
3. **Example: Creating a ThemeProvider**
    
    * Suppose you want to change the main colour of your app dynamically.
        
    * You can create a `ThemeProvider` class that extends `ChangeNotifier`.
        
    * It exposes a `mainColor` value and a `changeThemeColor` function to update it.
        
    * When the `mainColor` changes, the class notifies its listeners using `notifyListeners()` .
        
4. **Usage: Wrapping the Widget Tree**
    
    * In your app, wrap the root widget (usually `MaterialApp`) with a `ChangeNotifierProvider<ThemeProvider>`.
        
    * Use a `Consumer<ThemeProvider>` widget to access the value of `ThemeProvider` within your widgets.
        
    * For example:
        
        ```dart
        class MyApp extends StatelessWidget {
          @override
          Widget build(BuildContext context) {
            return ChangeNotifierProvider<ThemeProvider>(
              create: (context) => ThemeProvider(),
              child: Consumer<ThemeProvider>(
                builder: (context, themeProvider, child) => MaterialApp(
                  // Your app content here
                ),
              ),
            );
          }
        }
        ```
        
    * Now any child widget can access and update the main color using `ThemeProvider.mainColor` .
        

---

## How to Use provider in a Flutter Project

**Provider** is a powerful state management solution for Flutter. Let’s walk through the steps to use it in your project:

1. **Add the Provider Package**:
    
    * Open your `pubspec.yaml` file and add the `provider` dependency:
        
        ```yaml
        dependencies:
          flutter:
            sdk: flutter
          provider: ^6.1.2
        ```
        
    * Run `flutter pub get` to fetch the package.
        
2. **Create a Provider Class**:
    
    * Create a new Dart file (e.g., `data.dart`) to store your data.
        
    * Define a class (e.g., `Counter`) that extends `ChangeNotifier`.
        
    * Inside this class, declare your state variables (e.g., `_count`).
        
3. **Expose State with the Provider**:
    
    * In your `Counter` class, provide methods to modify the state (e.g., incrementing the count).
        
    * Use `notifyListeners()` to notify listeners when the state changes.
        
4. **Wrap Your App with the Provider**:
    
    * In your `main.dart`, wrap your app with a `ChangeNotifierProvider`:
        
        ```dart
        void main() {
          runApp(
            ChangeNotifierProvider(
              create: (context) => Counter(),
              child: MyApp(),
            ),
          );
        }
        ```
        
5. **Access State in Widgets**:
    
    * Use `Consumer<Counter>` to access the state within your widgets:
        
        ```dart
        Consumer<Counter>(
          builder: (context, counter, child) {
            return Text('Count: ${counter.count}');
          },
        )
        ```
        

---

## `ChangeNotifierProvider` in Flutter:

**ChangeNotifierProvider** is a class from the **provider** package in Flutter that links the lifecycle of a `ChangeNotifier` to widgets in the widget tree. Let’s break it down:

1. **What is a**`ChangeNotifier`?
    
    * A `ChangeNotifier` is a simple class in the Flutter SDK that provides change notification to its listeners.
        
    * When something is a `ChangeNotifier`, you can subscribe to its changes. It acts as an observable, notifying listeners when its internal state changes.
        
2. **How does**`ChangeNotifierProvider` work?
    
    * `ChangeNotifierProvider` is responsible for creating and supplying an instance of a `ChangeNotifier` directly to the UI.
        
    * It ensures that when the `ChangeNotifier` emits a signal(due to changes).,dependent widgets are notified and can rebuild accordingly.
        
3. **Difference between**`ChangeNotifierProvider` and `Provider`:
    
    * The `Provider` class exposes a value to all widgets but doesn’t listen to changes from that value.
        
    * In contrast, `ChangeNotifierProvider` listens to changes from the `ChangeNotifier` and provides the updated values to dependent widgets.
        

So, if you want to manage state using a `ChangeNotifier`, use `ChangeNotifierProvider` to integrate it seamlessly into your Flutter app!

---

## `MultiProvider` in Flutter

In Flutter, `MultiProvider` is a powerful widget provided by the `provider` package. It allows you to combine multiple providers into a single widget tree. Here’s how it works:

1. **Combining Multiple Providers:**
    
    * Suppose you have different data models (e.g., `ChatProvider`, `MessageProvider`) that you want to use across your app.
        
    * You can wrap your widget tree with a `MultiProvider` and provide a list of providers. Each provider corresponds to a specific data model.
        
    * For example:
        
        ```dart
        MultiProvider(
          providers: [
            ChangeNotifierProvider<ChatProvider>(
              create: (context) => ChatProvider(),
            ),
            ChangeNotifierProvider<MessageProvider>(
              create: (context) => MessageProvider(),
            ),
            // Add more providers as needed
          ],
          child: YourApp(),
        )
        ```
        
2. **Accessing Providers:**
    
    * Once you’ve set up the `MultiProvider`, you can access the provided data models using `Provider.of<T>(context)`.
        
    * For instance, in your widget, you can use:
        
        ```dart
        final chatProvider = Provider.of<ChatProvider>(context);
        final messageProvider = Provider.of<MessageProvider>(context);
        ```
        
3. **Context Hierarchy:**
    
    * The context hierarchy matters. Providers should be above the widgets that need access to them.
        
    * If you want to use providers across different routes, place the `MultiProvider` above your `MaterialApp`.
        
    * However, having multiple `MaterialApp` widgets is not recommended. Instead, consider passing the providers as values to new routes without nesting additional `MaterialApp` widgets.
        

---

## Best Practices for organising provider setup:

Certainly! Organising your **Provider** setup effectively is crucial for maintaining a clean and scalable Flutter app. here are some best practices:

1. **Separate Concerns:**
    
    * Divide your code into logical layers: UI, business logic, and data.
        
    * Place UI-related widget in separate files(e.g.,`screens`, `widgets` folders).
        
    * Keep business logic (providers)in their own files(e.g.,`providers` folder)
        
2. **Provider Classes:**
    
    * Create separate provider classes for different data models or features.
        
    * For example, if you have tasks and user authentication, create `TaskProvider` and `AuthProvider`.
        
3. **Nested Providers**:
    
    * Use nested providers when one provider depends on another.
        
    * For instance, if a `TaskList` widget needs access to both tasks and user data, nest `TaskProvider` and `AuthProvider` .
        
4. **Provider Tree:**
    
    * Visualise your provider tree. Understand which widgets depend on which providers.
        
    * Avoid unnecessary providers at the root level. Only expose what's needed.
        
5. **Scoped Providers:**
    
    * Use `Provider.of` or `Consumer` for specific widgets that need access to a provider.
        
    * Avoid using `Provider.of` at the root level unless it's truly global state.
        
6. **Provider Architecture:**
    
    * Consider using a layered architecture(e.g., Clean Architecture)with providers.
        
    * Separate data sources (API, local storage) from business logic providers.
        
7. **Value vs. ChangeNotifier:**
    
    * Use `ChangeNotifierProvider` for mutable state(e.g.,tasks, user preferences).
        
    * Use `Provider.value` for immutable data (e.g., constants, configuration).
        
8. **Dispose Resources:**
    
    * Clean up resources(e.g.,close streams, cancel subscriptions) in your provider's `dispose` method.
        
    * Avoid memory leaks.
        
9. **Testing**:
    
    * Write unit tests for your providers.
        
    * Use `ProviderScope` in your tests to isolate providers.
        
10. **Localisation and Themes**:
    
    * Consider using providers for localisation (language) and themes (dark mode, light mode).
        

---

> Using the **Provider** package for state management in Flutter offers a scalable solution for managing application state. By leveraging `ChangeNotifierProvider` and other provider classes, developers can efficiently handle state changes and ensure their apps remain maintainable and testable. Organising your provider setup with best practices, such as separating concerns and using nested providers, enhances the structure and readability of your code. Whether managing simple state or complex data models, **Provider** simplifies the process, making it an essential tool for any Flutter developer.

%%[linkedinwidget]
