Comments (11)
Oh, I think I got confused about the issue. I'll investigate. Sounds like a bug for sure.
Thanks for the report.
from riverpod.
It depends on the changes involved. But if it has to be a 3.0.0 fix, you could always stick to using your fork in the meantime
from riverpod.
All of that sounds normal to me.
A
was mounted, and A
is listening to B
. So B
is indeed listened.
Even though A
is unused, it still needs to listen to B
. After-all if B
is recomputed, A
will have to be recomputed the next time it is used.
from riverpod.
I guess I just expected both A
and B
to be disposed when I leave the page and wait. I expected the state of B
to be reset when I go back to the page the second time, but it remains. Why should a disposed resource A
keep its dependencies B
alive forever?
I find it weird that an unused auto-dispose provider leaves a listener attached to its dependency forever. This fundamentally causes a memory leak because if you:
- Navigate to
SomeScreen
- Go back
- Repeat steps 1-2 many times
In the end, you'll only have one SomeScreen
mounted, so A
will end up with one listener. B
will have 1 useful listener and many other "ghost" listeners that are never cleared. So if those steps are repeated, you end up with 1 million listeners on B
even though only one of them is for a resource that isn't disposed? There's no way that this can be expected behavior.
Why doesn't the watch method in A
check if A
is used/not disposed before adding the listener to B
?
from riverpod.
My project relies on this task being fixed urgently. If I were to make a PR and it's merged successfully, could it be a part of a minor release, or would it have to wait until 3.0?
from riverpod.
I'm not exactly sure how to fix this. If provider a
in my example is disposed since we left the screen, should it be allowed to watch anything? Or should a
wait until it has no listeners and its build is completed before disposing?
from riverpod.
@rrousselGit I managed to fix it by simply checking the _mounted
status in ref functions and throwing error if not but I don't know if it could cause any other issues?
here's the pr #3598
from riverpod.
I've got the same bug (which was hard to catch).
A temporary solution is to update aProvider to watch the future before the await:
@riverpod
Future<int> a(ARef ref) async {
print('buildA');
ref.onAddListener(() {
print('addA');
});
ref.onRemoveListener(() {
print('removeA');
});
ref.onCancel(() {
print('cancelA');
});
final bFuture = ref.watch(bProvider.future);
await Future.delayed(const Duration(seconds: 5));
await bFuture;
return 5;
}
from riverpod.
@AhmedLSayed9 that kinda works but you would end up making that network call even if provider is disposed and there's no need. also it gets quite messy the more futures you have in your provider.
but if you ok with waiting all those futures even when disposed you might want to consider keepAlive
link instead in this case you only have 2 extra lines no matter how many futures you have
@riverpod
Future<int> a(ARef ref) async {
print('buildA');
ref.onAddListener(() {
print('addA');
});
ref.onRemoveListener(() {
print('removeA');
});
ref.onCancel(() {
print('cancelA');
});
final keepAliveLink = ref.keepAlive(); // make it non disposable
await Future.delayed(const Duration(seconds: 5));
await ref.watch(bProvider.future);
keepAliveLink.close(); // release
return 5;
}
from riverpod.
you would end up making that network call even if provider is disposed
This would occur in both cases. I'd use CancelToken
for that matter anyway.
you might want to consider keepAlive link instead
The KeepAliveLink
will prevent aProvider
from being disposed if bProvider
throws an error.
from riverpod.
This would occur in both cases. I'd use CancelToken for that matter anyway.
Yup that's why I said if you ok with that. Some requests unfortunately can't be canceled e.g supabase db calls, etc
The KeepAliveLink will prevent aProvider from being disposed if bProvider throws an error.
Fair enough. You'd want to have a wrapper function that would handle with try/catch/finally which gets quite ugly regardless.
The proper solution is to just throw when trying to use watch/listen of disposed refs which is coming in v3. For now we may just have to stick to a fork
from riverpod.
Related Issues (20)
- `ref.exists()` returns `true` when manually invalidate a provider.
- `yarn dev -l {LANG}` is needed when hosting documentation website locally for specific locale with docusaurus
- Stream from StreamProvider is not unsubscribed to when widgets get disposed HOT 3
- There is no way to handle the "done" event on the stream of a StreamProvider
- `ref.invalidate(familyProvider)` is not working with scoped providers
- PageController stateprovider doesn't work when .previousPage() or nextPage() is pressed HOT 1
- beforeDispose or beforeInvalidate hook, happen before invalidate HOT 6
- Multiple invalidation of Providers HOT 2
- Unable to use the latest riverpod in flutter version lower than 3.16 HOT 2
- The getter 'variable2' isn't defined for the class 'PropertyAccessorElement'. HOT 10
- Can't copy code snippet from main landing page in website HOT 2
- Infinitely call child's `useEffect` when parent and child both `extends HookConsumerWidget` HOT 2
- riverpod_lint didn't show assists (in context menu) HOT 10
- Would separating asyncValue into its own package be useful? HOT 1
- Overriden providers are not passed to dialogs or modals HOT 5
- Unexpected dispose behavior in AutoDisposeProvider with nested watch methods HOT 3
- `Provider1` will never get disposed if `Provider2` gets disposed before it listens to or watches `Provider1` HOT 1
- Provider delegates onCancel and onDispose aren't invoked after invalidation when there are no remaining listeners HOT 3
- state works weird HOT 1
- Provider gets disposed before future completes when using `ref.read(provider.future)` HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from riverpod.