How to correctly extend a custom Provider in Flutter

485

Provider.of looks for provider with exactly given type. It doesn't include child types.

If the child screen needs to access some different data having same format, you can use the same provider in both cases passing it different data through constructor:

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (condition) {
      return ChangeNotifierProvider(
        create: (context) => ParentProvider(data1),
        child: _Screen(),
      );
    }
    return ChangeNotifierProvider(
      create: (context) => ParentProvider(data2),
      child: _Screen(),
    );
  }
}

If you really have two different ChangeNotifier implementations sharing same interface, you can provide and access them using parent type:

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (condition) {
      return ChangeNotifierProvider<ParentProvider>(
        create: (context) => ChildProviderA(),
        child: _Screen(),
      );
    }
    return ChangeNotifierProvider<ParentProvider>(
      create: (context) => ChildProviderB(),
      child: _Screen(),
    );
  }
}
Share:
485
Ismaeel Sherif
Author by

Ismaeel Sherif

Updated on December 31, 2022

Comments

  • Ismaeel Sherif
    Ismaeel Sherif over 1 year

    I have a parent ChangeNotifier ParentProvider, and 2 other providers extend the ParentProvider;

    ChildProviderA, ChildProviderB.

    I have a route which is called MyScreen

    class MyScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
    
        if(ModalRoute.of(context).settings.arguments != null){
          return ChangeNotifierProvider(
            create: (context) => ChildProviderA(),
            child: _Screen()
          );
        }
        return ChangeNotifierProvider(
          create: (context) => ChildProviderB(),
          child: _Screen()
        );
      }
    }
    

    depending on the arguments I want to use a provider, and in either case, I want to call a function called initData() in the ParentProvider from the _Screen widget.

    @override
      Widget build(BuildContext context) {
    ...
        Provider.of<ParentProvider>(context, listen: false).initData();
    ...
    }
    

    This gives me an error

    Error: Could not find the correct Provider<ParentProvider> above this _Screen Widget
    

    If I used Provider.of<ChildProviderA>(context, listen: false).initData();

    or Provider.of<ChildProviderB>(context, listen: false).initData(); It works, but I want in either child Provider used, to be able to call initData.

    How can this be done ?

  • Ismaeel Sherif
    Ismaeel Sherif over 2 years
    this is what I have done, but it doesn't work
  • Huthaifa Muayyad
    Huthaifa Muayyad over 2 years
    You need to put all of them above your widget.
  • Ismaeel Sherif
    Ismaeel Sherif over 2 years
    The second example works. It still needed to declare an empty method in the ParentProvider to be able to run it from ChildA, but anyway it saved a lot of code
  • Ismaeel Sherif
    Ismaeel Sherif over 2 years
    do you mean I should use the 3 providers in the route ?
  • Pavel
    Pavel over 2 years
    To avoid empty methods in parent change notifier, you can make the parent class abstract and declare abstract method
  • Pavel
    Pavel over 2 years
    @HuthaifaMuayyad Provider.of uses getElementForInheritedWidgetOfExactType which doesn't look for subtypes, only exact given type
  • Ismaeel Sherif
    Ismaeel Sherif over 2 years
    @Huthaifa I think I understood your solution, but it will contain a lot of extra functions in both child classes which just points to parent functions