rrousselGit / riverpod

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

(repurposed) Document that invalidate() may not cause a refresh if the provider isn't listened. #3773

Open nateshmbhat opened 1 month ago

nateshmbhat commented 1 month ago

Describe the bug ref.invalidateSelf is not triggering a refresh (read) but documentation says that invalidateSelf will refresh the provider.

To Reproduce

final profileStatsInfoProvider = FutureProvider<ProfileStatsResponseModel>(
  (ref) async {
    final api = ref.read(profileStatsApiProvider);
    final userId = ref.watch(userIdProvider);
    print('reading provider')
    ref.listen(mySessionProvider, (previous, next) {
        Future.delayed(1.seconds, (){ 
            print('invalidated self');
            ref.invalidateSelf();
        });
    }, fireImmediately: false);
    return api.getProfileInfo(userId: userId);
  },
);

When mySessionProvider updates : I only see log which says : "invalidated self" , but after this, i don't see "reading provider" log.

Expected behavior : both "invalidated self" followed by "reading provider" should get logged

nateshmbhat commented 1 month ago

my requirement is such that i want to passively listen for mySessionProvider and when its updated, want to refresh this profileStatsInfoProvider only after 1 second.

rrousselGit commented 1 month ago

Th refresh only happens if the provider is listened.

From your code, it is unclear if your provider is listened or not. So I'll assume it isn't and that the behavior is expected.

nateshmbhat commented 1 month ago

thanks so much for replying so quickly 🙏🏻 understood. is there a recommended way to preload the provider and keep it alive without using ref.watch at the top level widget ?

class MiracleApp extends HookConsumerWidget {
  const MiracleApp({super.key});

  void initializeCoreDataProviders(WidgetRef ref) {
    ref.read(userStatsSummaryProvider);
    ref.read(meditationSelectorProvider);
    ref.read(profileStatsInfoProvider);
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    useEffect(() {
        initializeCoreDataProviders(ref);
    }, const []);

    return MaterialApp.router(
      title: 'My App',
      routerConfig: appRouter,
    );
  }
}

in the above example, i'm initializing some core providers which i will be listening to in some other screens at later point in time but i want the data in these providers ready and loaded without getting disposed off.

2 Questions here :

  1. is it advisable to do ref.watch(profileStatsInfoProvider) here ? i don't want it to re-build this MiracleApp widget since i'm not using it here in this widget. what's the better alternative ?
    1. is it advisable to have ref.listen called here and keep a reference to the subscription object and then dispose it off when this MiracleApp widget is getting disposed ? what do u recommend ?
    2. basically, I don't want it to get disposed without refreshing it immediately.

how do i do this ?

nateshmbhat commented 1 month ago

i thought only AutoDisposeProviders get disposed off when there are no listeners, how do i get the always alive behavior ? do i have to use AutoDisposeProvider and then explicitly call ref.keepAlive( ) for this behavior ? seems little counter intuitive just to keep the provider alive. :thi

rrousselGit commented 1 month ago

Just switch read to something else that listens to the provider. So either watch or listen. It's up to you.

nateshmbhat commented 1 month ago

here's my question :

if AutoDisableProvider is supposed to get auto disposed and there's a way to keep it alive even when there are no listeners by calling ref.keepAlive()

By using a Provider directly (which suggests that it won't auto dispose) , i would expect the provider to be kept alive even if there are no listeners. Or at least there should be a way to keep it alive.

If i want this behavior, then using AutoDisposableProvider seems to be counter intuitive. What do u think ?

rrousselGit commented 1 month ago

I do not understand your question unfortunately

nateshmbhat commented 1 month ago

ok , so i had a misunderstanding that calling ref.keepAlive( ) will ensure it will re-build right away after invalidating even when there are no listeners. that's why was asking questions related to ref.keepAlive for an auto dispose provider. pls ignore that.

I think the doc in the code comments need to be updated : for invalidateSelf method it says the following :

Invalidates the state of the provider, causing it to refresh.

The refresh is not immediate and is instead delayed to the next read or next frame.

Calling [invalidateSelf] multiple times will refresh the provider only once.

Calling [invalidateSelf] will cause the provider to be disposed immediately.

Invalidates the state of the provider, causing it to refresh. this is not fully correct. It will cause a refresh as long as there are listeners attached.