Panda World
Panda World

Reputation: 1996

Riverpod StateNotifier lost state when parent provider refresh

I have been trying to work out a solution for it but no luck. The key problem here is when you have a StateNotifier that depends on another provider, A fresh from the parent provider will cause the StateNotifier to be regenerated and result in existing state lost. I will use a simple example to explains my problem. Here are the providers:

class Pair {
  final int parentValue;
  final int childValue;

  Pair({required this.parentValue, required this.childValue});

  Pair copyWith({int? parentValue, int? childValue}) {
    return Pair(
        parentValue: parentValue ?? this.parentValue,
        childValue: childValue ?? this.childValue
    );
  }
}

class PairNotifier extends StateNotifier<Pair> {
  // parentValue comes from counterProvider but childValue is maintained in existing notifier
  PairNotifier(int parentValue): super(Pair(parentValue: parentValue, childValue: 0));

  Pair increment() {
    final value = state.childValue + 1;
    state = state.copyWith(childValue: value);
    return state;
  }
}

final counterProvider = StateProvider((ref) => 0);

final pairStateProvider = StateNotifierProvider<PairNotifier, Pair>((ref) {
  //Image there are more watch in real world case.
  final parentValue = ref.watch(counterProvider); 
  // when counter is updated, PairNotifier is regenerated therefore childValue is lost.
  return PairNotifier(parentValue);
});

I would like to know if there is a way to preserve the existing state when all its' parent providers refreshed. Surely there should be a elegant solution since this library has been out there for quite some time.

Upvotes: 1

Views: 1150

Answers (1)

narayann
narayann

Reputation: 481

i also got these issue, Actually there are 2 type of ref objects WidgetRef and ProviderRef.

  • In simple WidgetRef used inside widget tree
  • ProviderRef is used to communicate between providers

So in widget you will watch the providers and its values, but as in our case we try to watch providers inside another provider, actually we need to read the provider data inside another provider. If we watch provider data, it will change when another provider data is changed/ manipulated.

In short, use ref.read() method

final counterProvider = StateNotifierProvider<Counter, int>((ref) {
  return Counter(ref);
});

class Counter extends StateNotifier<int> {
  Counter(this.ref): super(0);

  final Ref ref; //it is provided ref

  void increment() {
    // Counter can use the "ref" to read other providers

    final repository = ref.read(repositoryProvider);

    //in side provider we dont want to watch any changes 
    //we only need to read the data of other provider
    repository.post('...');
  }
}

for more you can go through official doc

Upvotes: 2

Related Questions