Search code examples
flutterdartglobalproviderriverpod

Riverpod's reference-based system seems to work like a global in a specific case. What am I doing wrong?


Is this a case where I should be using a traditional (pre-riverpod) widget-based provider or does riverpod have a solution for the following scenario?

I have a 'page' Widget with a listview of items. I instantiate this page class/Widget in two tabs, one for live items and the other as a trash/bin.

Currently I'm passing an 'is_trash' boolean through the constructor of each instantiation and also the constructors of many custom sub-widgets so they can know to grey things out etc.

A provider is the obvious way to avoid messing with constructors just for one boolean.

So the traditional way is :


class MyPage extends StatelessWidget{
   bool isTrashView;
   
   MyPage(this.isTrashView);
   
   Widget build(context){
      return Provider<bool>.value(
         value : isTrashView,
         child : MyCustomList(/*don't need an isTrashView parameter here*/),      
      );
   }

}

class MyCustomList extends StatelessWidget{

   Widget build(context){
       bool isTrashView=Provider<bool>.of(context).value;
       return &etc........

   }

}

...and each instance of the MyPage widget gets its own unique provider.

Since riverpod uses globals for the providers, I can't set up unique providers in the two page instances to be read by some sub-widget as they would be sharing the provided variable and overwriting each other's data.

(I realise I've been a touch verbose: I'm trying to be clear for other beginners to riverpod stumbling across this thread.)


Solution

  • Remi answered me on Reddit. The solution was to use ScopedProvider for the data, and ProviderScope in the custom widget:

    final isTrashView = ScopedProvider<bool>((_) => false);
    
    class MyCustomWidget extends StatelessWidget {
      const MyCustomWidget({this.trashView = false});
    
      final bool trashView;
    
      @override
      Widget build(BuildContext context) {
        return ProviderScope(
          overrides: [
            isTrashView.overrideWithValue(trashView),
          ],
          child: AnotherCustomWidget(),
        );
      }
    }
    
    class AnotherCustomWidget extends ConsumerWidget { 
       const AnotherCustomWidget({Key? key}) : super(key: key);
       
       @override
       Widget build(BuildContext context, ScopedReader watch) {
         final trashView = watch(isTrashView);
         // etc.
       }
    }