Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StateNotifierProvider always refreshs when invalidated #1708

Closed
claudius-kienle opened this issue Sep 30, 2022 · 4 comments
Closed

StateNotifierProvider always refreshs when invalidated #1708

claudius-kienle opened this issue Sep 30, 2022 · 4 comments
Labels
bug Something isn't working needs triage

Comments

@claudius-kienle
Copy link

claudius-kienle commented Sep 30, 2022

Describe the bug
Once a StateNotifierProvider was created (e.g. via ref.watch(provider), it cannot be invalidated with ref.invalidate(provider), even though the widget that called ref.watch was disposed long ago and nothing else is listening.
I further analyzed the problem and figured out that the StateNotifierProvider is the only Provider calling ref.watch in their create() in base.dart:

class StateNotifierProvider<Notifier extends StateNotifier<State>, State>
...
  @override
  State create(ProviderElementBase<State> ref) {
    final notifier = ref.watch(this.notifier);

    void listener(State newState) {
      ref.setState(newState);
    }

    final removeListener = notifier.addListener(listener);
    ref.onDispose(removeListener);

    return ref.requireState;
  }
...

This call to ref.watch adds the _NotifierProvider, inialized during StateNotifierProvider's inialization, to the ProviderElement's _depenents once the StateNotifierProvider was created.

Later upon ref.invalidate, the StateNotifierProvider is refreshed since hasListeners is true in scheduler.dart:

void _performRefresh() {
  /// No need to traverse entries from top to bottom, because refreshing a
  /// child will automatically refresh its parent when it will try to read it
  for (var i = 0; i < _stateToRefresh.length; i++) {
    final element = _stateToRefresh[i];
    if (element.hasListeners) element.flush();
  }
}

To Reproduce
I created a minimal app which reproduces the bug. Just note the reaccuring state notifier initialized when clicking on Invalidate Providers.

Expected behavior
Expected behavior is that the StateNotifierProvider will not be refreshed as no listener (in the client code) is attached. Therefore, the ref.watch called in the create method must be disposed while the StateNotifierProvider is disposed.

I already created an issue (#1704) which did not describe the issue that clearly. Therefore, I closed that one to describe the bug in this issue in more detail.

@rrousselGit
Copy link
Owner

I'm pretty sure that what you're describing was fixed some long ago on master.

The dev release is quite out of date. I'd suggest trying the same thing with a git dependency on master to see if it still happens.

@claudius-kienle
Copy link
Author

Yess indeed it is working successfully on the master branch.
I am wondering why exactly is the dev release so far behind?

@rrousselGit
Copy link
Owner

A released is planned today

@claudius-kienle
Copy link
Author

A nice:) Thanks for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs triage
Projects
None yet
Development

No branches or pull requests

2 participants