How to scope providers on several widgets without putting the provider on a root widget in flutter

Viewed 870

I'm working on a simple demo where the user logs in, sees a list of items, clicks on an item, and then sees its details. These are 3 screens but let's say two flows where one deals with login and the other with items.

I'm managing my state using provider package. I placed a LoginRepository provider on my root widget because that state is needed everywhere. This works great.

Now I need an ItemRepository which should be available on the ItemListScreen and the ItemDetailScreen. To implement that scoping, I decided to create a common ancestor widget called ItemScreens. This is where I placed my provider and my nested Navigator.

I navigate my screens using Navigator.of(context) to make sure the closes ancestor navigator is used. I fetch my provider using Provider.of<ItemRepository>(context) to make sure the closes ancestor state is used.

This apparently does not work because I get a Could not find the correct provider. I understand that the provider from the sibling route cannot be accessed by another sibling but here I'm nesting navigators I would expect the ItemRepository to be placed at ItemScreens which then handles subrouting so that these two routes can fetch providers from the parent route?

Sidenote:
Flutter documentation clearly states that providers should be lifted to achieve proper scoping. But I've never seen an example where the provider was lifted to a non-root widget. If all we can do is place providers into the root widget, that should be clearly stated.

EDIT: Re-creating providers on several widgets is kind of an alternative but that's not really scoping it's just pseudo passing by value.

EDIT: Putting all providers on the root widget with MultiProvider isn't a good idea because it creates a global state anti-pattern. Some states should also simply not be created unless needed i.e. the user is visiting that flow/screen.

1 Answers

You can wrap your MaterialApp Widget in main.dart with Multiprovider and give the list of providers you are using, That way App knows which class to treat as providers.

MultiProvider(
        providers: [
          ChangeNotifierProvider(
            create: (_) => FirstProvider(),
          ),
          ChangeNotifierProvider(
            create: (_) => SecondProvider(),
          ),
        ],
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Auro',
          home: _decideMainPage(context),
          // routes: routes,
          theme: AllCoustomTheme.getThemeData(),
        ),
      )

Related