2

Minimal reproducible code:

final fooProvider = StateProvider<int>((ref) => 0);

final barProvider = Provider<String>((ref) {
  ref.watch(fooProvider); // 1
  return '';
});

class FooPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      body: BarPage(),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(fooProvider.notifier).state++, // 2
      ),
    );
  }
}

class BarPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    print('build(BarPage)'); // 3
    final string = ref.watch(barProvider); // 4
    return Text(string);
  }
}

1: barProvider is watching fooProvider.

2: I am changing fooProvider state.

4: I am watching barProvider (which itself is watching fooProvider, see 1)

3: This should have printed but it didn't.

iDecode
  • 22,623
  • 19
  • 99
  • 186
  • 1
    The value of barProvider does not change, so a ref.watch is not obligated to trigger a rebuild. in fact, it shouldn't! – Randal Schwartz Sep 25 '22 at 09:08
  • @RandalSchwartz Yes, the value of `barProvider` didn't change but isn't it listening to the changes in the `fooProvider`? – iDecode Sep 25 '22 at 09:09
  • 1
    the riverpod framework will only cause a rebuild in step 4 if newState != oldState. Since newState is always '', the check returns false, so riverpod will not update – Shazamo Morebucks Sep 25 '22 at 14:32

2 Answers2

1

The value returned by your provider is always ''

As such, Provider detects that the value exposed did not change, and does not notify listeners.

If you placed a print inside barProvider, you would see that the provider got rebuilt.

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
0

Following Remi Rousselet's answer,

Try creating a "wrapper" for the String, like so:

class Wrapper{
  final String value;
  Wrapper(this.value);
}


final fooProvider = StateProvider<int>((ref) => 0);

final barProvider = Provider<Wrapper>((ref) {
  ref.watch(fooProvider); // 1
  return Wrapper('');
});

class FooPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      body: BarPage(),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(fooProvider.notifier).state++, // 2
      ),
    );
  }
}

class BarPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    print('build(BarPage)'); // 3
    final string = ref.watch(barProvider); // 4
    return Text(string.value);
  }
}
Josteve
  • 11,459
  • 1
  • 23
  • 35
  • Your code won't compile. You will also need to change the `Provider` to `Provider` and then replace the `Text(string)` with `Text(string.value`). In other words, your code just changed my original type from `String` to `Wrapper`. – iDecode Sep 25 '22 at 14:45
  • Uh, right..I've made edits. – Josteve Sep 25 '22 at 14:48