rrousselGit / riverpod

A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze.
https://riverpod.dev
MIT License
6.17k stars 943 forks source link

ChangeNotifierProvider is not triggering state update in FutureProvider #114

Closed hayatae closed 4 years ago

hayatae commented 4 years ago

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().

rrousselGit commented 4 years ago

Do you have a complete example?

hayatae commented 4 years ago

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.

rrousselGit commented 4 years ago

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 .

hayatae commented 4 years ago

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:

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?

rrousselGit commented 4 years ago

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

rrousselGit commented 4 years ago

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

rrousselGit commented 4 years ago

flutter_hooks 0.14.0 was released Upgrading it should be enough