Closed a1573595 closed 1 month ago
This is expected. The ProviderSubscription was already closed my Riverpod by the time you called .read()
Riverpod closes all subscriptions associated to a widget when the widget is unmounted. So you cannot use sub.read()
after the widget got unmounted – which is what you do here.
This is expected. The ProviderSubscription was already closed my Riverpod by the time you called
.read()
Riverpod closes all subscriptions associated to a widget when the widget is unmounted. So you cannot use
sub.read()
after the widget got unmounted – which is what you do here.
So there is currently no other solution to cache data?
I hope not to load all the DataSource at once when entering NextPage, and release the KeepAliveLink of DataSource after leaving NextPage.
The issue is likely your Future
wrapping the .read()
I guess removing it should work
The issue is likely your
Future
wrapping the.read()
I guess removing it should work
I thought so before, but actually it's not.
Removing the future wrapping throws an error:
Having a Future throws an error:
Sounds like you used Future
to cheat around the error. That wasn't really supported
Looks like Consumer supports calling sub.read
inside ConsumerState.dispose
. Sounds like we would want to support this for useEffect.
Do you mind opening a feature request for this?
Describe the bug Update ProviderSubscription value throw Bad state exception in hooks_riverpod 2.5.1, 2.4.10 is well.
To Reproduce
Code sample
```dart import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; void main() { runApp(const ProviderScope(child: MaterialApp(home: HomePage()))); } final keepAliveLock = StateProvider.autoDispose((ref) => false); final dataSource1 = FutureProvider.autoDispose((ref) { final link = ref.keepAlive(); ref.listen(keepAliveLock, (previous, next) { link.close(); }); return Future.delayed(const Duration(seconds: 3), () => "Data1"); }); final dataSource2 = FutureProvider.autoDispose((ref) { final link = ref.keepAlive(); ref.listen(keepAliveLock, (previous, next) { link.close(); }); return Future.delayed(const Duration(seconds: 3), () => "Data2"); }); final dataSource3 = FutureProvider.autoDispose((ref) { final link = ref.keepAlive(); ref.listen(keepAliveLock, (previous, next) { link.close(); }); return Future.delayed(const Duration(seconds: 3), () => "Data3"); }); class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Center( child: TextButton( onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => const NextPage())), child: const Text("Next"), ), ), ); } } class NextPage extends HookConsumerWidget { const NextPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final pages = useMemoized(() => const [ FirstPage(), SecondPage(), ThirdPage(), ]); final tabController = useTabController(initialLength: pages.length); useEffect(() { final subscription = ref.listenManual(keepAliveLock.notifier, (prev, next) {}); return () { Future(() { subscription.read().update((state) => !state); subscription.close(); }); }; }, const []); return Scaffold( appBar: AppBar(), body: TabBarView( physics: const BouncingScrollPhysics(), controller: tabController, children: pages, ), ); } } class FirstPage extends ConsumerWidget { const FirstPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Center( child: ref.watch(dataSource1).when( data: (data) => Text(data), error: (error, stackTrace) => Text(error.toString()), loading: () => const CircularProgressIndicator(), ), ); } } class SecondPage extends ConsumerWidget { const SecondPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Center( child: ref.watch(dataSource2).when( data: (data) => Text(data), error: (error, stackTrace) => Text(error.toString()), loading: () => const CircularProgressIndicator(), ), ); } } class ThirdPage extends ConsumerWidget { const ThirdPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Center( child: ref.watch(dataSource3).when( data: (data) => Text(data), error: (error, stackTrace) => Text(error.toString()), loading: () => const CircularProgressIndicator(), ), ); } } ```Expected behavior No throw exception and release provider when ProviderSubscription close.