diff --git a/packages/flutter_riverpod/CHANGELOG.md b/packages/flutter_riverpod/CHANGELOG.md index 66a909dc5..3995f04ae 100644 --- a/packages/flutter_riverpod/CHANGELOG.md +++ b/packages/flutter_riverpod/CHANGELOG.md @@ -1,5 +1,6 @@ ## [Unreleased patch] +- It is now correctly possible to use `ProviderSubscription`s inside `ConsumerState.dispose` (thanks to @1980) - Update dependencies. ## 2.1.1 diff --git a/packages/flutter_riverpod/example/pubspec.yaml b/packages/flutter_riverpod/example/pubspec.yaml index 2bfdedaf1..ba3b4f460 100644 --- a/packages/flutter_riverpod/example/pubspec.yaml +++ b/packages/flutter_riverpod/example/pubspec.yaml @@ -8,7 +8,6 @@ environment: sdk: ">=2.17.0 <3.0.0" dependencies: - cupertino_icons: ^0.1.3 flutter: sdk: flutter flutter_riverpod: diff --git a/packages/flutter_riverpod/lib/src/consumer.dart b/packages/flutter_riverpod/lib/src/consumer.dart index dcd6aa893..5a99e2e8a 100644 --- a/packages/flutter_riverpod/lib/src/consumer.dart +++ b/packages/flutter_riverpod/lib/src/consumer.dart @@ -562,6 +562,10 @@ class ConsumerStatefulElement extends StatefulElement implements WidgetRef { @override void unmount() { + /// Calling `super.unmount()` will call `dispose` on the state + /// And [ListenManual] subscriptions should be closed after `dispose` + super.unmount(); + for (final dependency in _dependencies.values) { dependency.close(); } @@ -575,8 +579,6 @@ class ConsumerStatefulElement extends StatefulElement implements WidgetRef { } _manualListeners = null; } - - super.unmount(); } @override diff --git a/packages/flutter_riverpod/test/listen_test.dart b/packages/flutter_riverpod/test/listen_test.dart index 3c017601c..7a5831885 100644 --- a/packages/flutter_riverpod/test/listen_test.dart +++ b/packages/flutter_riverpod/test/listen_test.dart @@ -9,6 +9,16 @@ import 'utils.dart'; void main() { group('WidgetRef.listenManual', () { + testWidgets('returns a subscription that can be used within State.dispose', + (tester) async { + await tester.pumpWidget( + const ProviderScope(child: DisposeListenManual()), + ); + + // Unmounting DisposeListenManual will throw if this is not allowed + await tester.pumpWidget(ProviderScope(child: Container())); + }); + testWidgets('listens to changes', (tester) async { final provider = StateProvider((ref) => 0); final listener = Listener(); @@ -368,3 +378,34 @@ void main() { }); }); } + +final _provider = Provider((ref) => ''); + +class DisposeListenManual extends ConsumerStatefulWidget { + const DisposeListenManual({super.key}); + + @override + ConsumerState createState() => + _DisposeListenOnceState(); +} + +class _DisposeListenOnceState extends ConsumerState { + late final ProviderSubscription sub; + + @override + void initState() { + super.initState(); + sub = ref.listenManual(_provider, (prev, next) {}); + } + + @override + Widget build(BuildContext context) { + return Container(); + } + + @override + void dispose() { + sub.read(); + super.dispose(); + } +}