River_pod: ChangeNotifierProvider is not triggering state update in FutureProvider

Created on 4 Sep 2020  Â·  7Comments  Â·  Source: rrousselGit/river_pod

Describe the bug
Using hooks_riverpod: ^0.9.1, I am attempting to have the state of a FutureProvider re-evaluate as a result of changes in a ChangeNotifierProvider. As far as I understand, by calling ref.watch(appSettingsProvider) inside of the FutureProvider, it should be subscribing to notifyListeners() events from the ChangeNotifierProvider and re-evaluating its state. However, given the code below, the sub settings provider re-evaluate statement is only printed once ever. I have log statements adjacent to calls to notifyListeners() in the ChangeNotifierProvider and those are being executed, but I never see the FutureProvider update again.

To Reproduce

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final appSettingsProvider = ChangeNotifierProvider<AppSettingsProvider>(
    (ref) => AppSettingsProvider(ref));

class AppSettingsProvider extends ChangeNotifier { ... code which eventually calls notifyListeners(); }

final subSettingsProvider = FutureProvider<SubSettings>((ref) async {
  final appSettings = ref.watch(appSettingsProvider);
  final settings = await appSettings.settings;
  print('sub settings provider re-evaluate');
  return settings.subSettings;
});

Expected behavior
I expect the FutureProvider to re-evaluate any time the appSettingsProvider calls notifyListeners().

bug

Most helpful comment

I have tracked down the bug and found the fix (which is on flutter_hooks)

I'll write tests for it tomorrow and deploy it

All 7 comments

Do you have a complete example?

Here is a complete runnable example project which exhibits the issue:
https://github.com/hayatae/river_pod_bug

In testing further, I've found that the bug is only present when I try to update a useState value from within useEffect, so this might actually be a hooks issue rather than a river_pod issue? In the project above, if you comment out line 37 (test.value = subProvider.data.value.count;) in main.dart, everything works fine. With it uncommented, nothing updates.

What I was originally trying to accomplish here was to retrieve an initial value from a FutureProvider, and then cache the last result locally (via useState and useEffect) so that while the next value is pending, I can continue to display the previous value. Not really sure how to accomplish that effect with riverpod yet.

Indeed there is a bug, and it is likely on the hooks side. I'll investigate

On Sat, Sep 5, 2020, 00:49 hayatae notifications@github.com wrote:

Here is a complete runnable example project which exhibits the issue:
https://github.com/hayatae/river_pod_bug

In testing further, I've found that the bug is only present when I try to
update a useState value from within useEffect, so this might actually be
a hooks issue rather than a river_pod issue? In the project above, if you
comment out line 37 (test.value = subProvider.data.value.count;) in
main.dart, everything works fine. With it uncommented, nothing updates.

What I was originally trying to accomplish here was to retrieve an initial
value from a FutureProvider, and then cache the last result locally (via
useState and useEffect) so that while the next value is pending, I can
continue to display the previous value. Not really sure how to accomplish
that effect with riverpod yet.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/rrousselGit/river_pod/issues/114#issuecomment-687445456,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AEZ3I3KKJC64TVX5GVXURKLSEFVHXANCNFSM4QZOEOJA
.

In the mean time is there a better way to accomplish what I'm trying to achieve here? Basically what I need to do is the following:

  • Provide data to a component that will initially load asynchronously
  • After initial load, it may receive updates which cause another async load (ie. a settings change detected via ref.watch() might cause the data to need to re-query the databae)
  • I need to always be able to access the last-loaded value so that the page doesn't lose data from the user perspective, but it would also be nice if I could know when it's in the new loading state (ie. show previous values and also a small spinner in the corner of the page as opposed to removing all data from the page while loading the new values).

This kinda sounds like something that StreamProvider might be able to help with, but it's really cumbersome to deal with for a situation that occurs frequently in my app (needing to perform async fetch operations on settings changes).

The only other thing I could think of would be to create both a FutureProvider and a StateProvider for fetching new data and storing the last value, respectively. Then have a third standard Provider which watches both the FutureProvider and StateProvider and returns appropriate values as needed.

I'm kind of surprised that more people don't run into this situation. Maybe a possible feature improvement for FutureProvider or a new provider type entirely?

I wouldn't worry too much. I'll investigate tomorrow and will most likely push a fix.

Your approach is fine, and hooks are definitely a good use-case for this sort of problem. So this should be resolved shortly

I have tracked down the bug and found the fix (which is on flutter_hooks)

I'll write tests for it tomorrow and deploy it

flutter_hooks 0.14.0 was released
Upgrading it should be enough

Was this page helpful?
0 / 5 - 0 ratings