Home > Software design >  Flutter - Provider - Different ChangeNotifier instance for different context
Flutter - Provider - Different ChangeNotifier instance for different context

Time:10-22

I created two widgets from same custom StatefulWidget class. I want them to use separate ChangeNotifier instance from same ChangeNotifier derived class because they need to consume different data set. Unfortunately just like below example, it's not working like I want it to. Both read() and watch() respectively write and read data on the same ChangeNotifier instance.

Wait a minute. Isn't that what Provider supposed to do?. Yes I know. I'm aware that. But now I just need a little flexibility. I think I'm just using Provider the wrong way if I'm not wrong.

Thank you for your help. Greatly appreciate it.

MultiProvider App() => MultiProvider(
  ...
  providers : [
    ...
    ChangeNotifierProvider(create : (_) => Notifier()),
  ]
);

class TestState extends State<Test>{

  GlobalKey<CounterState> gk1 = GlobalKey<CounterState>();
  GlobalKey<CounterState> gk2 = GlobalKey<CounterState>();

  @override
  Widget build(BuildContext context){
    ...
    .. [Counter(gk1), Counter(gk2)]
    ...
    .. onPressed: (){
    ..  gk1.currentState?.increment(1);
    ..  gk2.currentState?.increment(2);
    .. },
    ...
  }
}

class CounterState extends State<Counter>{

  @override
  Widget build(BuildContext context){
    ...
    .. context.watch<Notifier>().count
    ...
  }

  void increment(int v){
    context.read<Notifier>().count  = v;
  }
}

class Notifier with ChangeNotifier{

  int _count = 0;

  int get count => _count;

  void set count(int v){
    _count = v;
    notifyListeners();
  }
}

CodePudding user response:

I remember facing this exact issue when I was using this package. I did a little search but couldn't find much info about it, so I decided to change approach.

Instead of having N providers of the same type, I now create 1 provider containing all the info for the N widgets.

In your case I would do something like:

class Notifier with ChangeNotifier{

  List<int> _counts = [0, 0];

  int getCountAt(int index) {
    return _counts[index]; //Control list lenght of course
  }

  void set count(int index, int v){
    _count[index] = v;
    notifyListeners();
  }
}

Relying on index to access the correct counter might not work. If that's the case, you can create a more complex object to access it's counter (maybe an id? a UniqueKey?).

CodePudding user response:

I guess there's no other way yet to solve this problem easily. Either I was missing something or Provider doesn't yet support binding with ChangeNotifier by any passed instance directly not by only a single instance of the class. So I marked Axel's as the answer for now.

But based on the example in the question, for my case I use state instance for the key to identify the different data set, and binding it with a "change notifier instance" exactly.

class CounterState extends State<Counter>{

  @override
  Widget build(BuildContext context){
    ...
    .. context.watch<Notifier>().instance(this).count
    ...
  }

  void increment(int v){
    context.read<Notifier>().instance(this).count  = v;
  }
}

class Notifier with ChangeNotifier{

  Map<State, NotifierInstance> _instance = {};

  NotifierInstance instance(State state){
    if(_instance[state] == null) _instance[state] = NotifierInstance(this);
    return _instance[state]!;
  }
}

class NotifierInstance{

  Notifier notifier;
  int _count = 0;

  NotifierInstance(this.notifier);

  int get count => _count;

  void set count(int v){
    _count = v;
    notifier.notifyListeners();
  }
}
  • Related