skip to Main Content

Is there an alternative method to initialize Provider rather than wrapping it with MaterialApp with MultiProvider?

I am currently using Provider to manage state in my Flutter app. I am wrapping my MaterialApp widget with MultiProvider to initialize all of my providers. However, I am wondering if there is a more efficient way to do this.

I have tried to create a provider while building a widget, but the issue right here was when navigating to another screen it shows provider not found exception and if we create a new instance on that widget the entire data is change.

Is there a way to initialize Provider without wrapping it with MaterialApp with MultiProvider? If so, what is the best way to do this?

Thanks for your help!

2

Answers


  1. I’m afraid there’s no alternative, if you want to declare multiple providers you will need to implement MultiProvider at some point, about using MaterialApp, that’s up to you, since you can implement MultiProvider without using MaterialApp but I don’t recommend you to do that since MaterialApp defines some constraints to how your app is rendered like margins to the top. About the other part of your question when you define a provider inside a widget this will only be available for child widgets this means widgets inside the parent one like:

    // This works, a child widget can access its parent provider
    ParentWidget(Defines Provider A) --> ChildWidget(Consumes Provider A)
    // this doesn't work, a parent widget can't access a provider defined on a nested widget
    ParentWidget(Cannot consume Provider A) --> ChildWidget(Defines Provider A) --> DeeperChildWidget(Consumes Provider A)
    

    Now that this is clear I would like to know, why do you want to avoid the use of MultiProvider is there an specific reason for that?

    Login or Signup to reply.
  2. You can create the providing on current route, but to access it, you need to separate the context.

    return ChangeNotifierProvider<Counter>(
      create: (_) => Counter(),
        child: Builder(
          builder: (context) {
            // we cant accass the context of the provider within same context while context
            return Scaffold(
    

    Now to pass the current provider on next route

    final value = context.read<Counter>();
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => ChangeNotifierProvider<Counter>.value(
          value: value,
          builder: (context, child) {
            return const NextPage();
          },
        ),
      ),
    );
    

    Test snippet

    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: HomePage(),
        );
      }
    }
    
    class Counter extends ChangeNotifier {
      int _count = 0;
    
      int get count => _count;
    
      void increment() {
        _count++;
        notifyListeners();
      }
    }
    
    class HomePage extends StatelessWidget {
      const HomePage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider<Counter>(
          create: (_) => Counter(),
          child: Builder(
            builder: (context) {
              // we cant accass the context of the provider within same context while context
              return Scaffold(
                  body: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Consumer<Counter>(
                      builder: (context, Counter counter, child) {
                        return Text("Count: ${counter.count}");
                      },
                    ),
                    ElevatedButton(
                      onPressed: () {
                        context.read<Counter>().increment();
                      },
                      child: const Text("Increment"),
                    ),
                    ElevatedButton(
                      onPressed: () {
                        final value = context.read<Counter>();
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => ChangeNotifierProvider<Counter>.value(
                              value: value,
                              builder: (context, child) {
                                return const NextPage();
                              },
                            ),
                          ),
                        );
                      },
                      child: const Text("Next Page"),
                    ),
                  ],
                ),
              ));
            },
          ),
        );
      }
    }
    
    class NextPage extends StatelessWidget {
      const NextPage({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Next Page"),
          ),
          body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Consumer<Counter>(
                  builder: (context, Counter counter, child) {
                    return Text("Count: ${counter.count}");
                  },
                ),
                ElevatedButton(
                  onPressed: () {
                    context.read<Counter>().increment();
                  },
                  child: const Text("Increment"),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search