0

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!

Nikhith sunil
  • 229
  • 3
  • 4

2 Answers2

1

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"),
            ),
          ],
        ),
      ),
    );
  }
}
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
0

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?

  • for small applications, Multiprovider is the best choice but in the case of an extensive large application with a large number of providers initializing all of it with Multi-provider is a kind of boilerplate also, it creates some issues on a large application [check this](https://github.com/rrousselGit/provider/issues/703) – Nikhith sunil May 30 '23 at 05:37