riverpod
riverpod copied to clipboard
[riverpod_lint] `provider_dependencies` seems to be missing collection of `ref.invalidate` method
Describe the bug
When I use ref.invalidate in my code lint does not prompt to include the provider in dependencies and when ref.invalidate fires I get an error that it needs to be included.
════════ Exception caught by gesture ═══════════════════════════════════════════
The following assertion was thrown while handling a gesture:
The provider bProvider:AutoDisposeAsyncNotifierProviderImpl<B, bool>#6153a tried to read aProvider:AutoDisposeAsyncNotifierProviderImpl<A, String>#60332, but it specified a 'dependencies' list yet that list does not contain aProvider:AutoDisposeAsyncNotifierProviderImpl<A, String>#60332.
To fix, add aProvider:AutoDisposeAsyncNotifierProviderImpl<A, String>#60332 to bProvider:AutoDisposeAsyncNotifierProviderImpl<B, bool>#6153a's 'dependencies' parameter
'package:riverpod/src/framework/element.dart':
Failed assertion: line 641 pos 11: 'listenable.dependencies == null ||
provider != origin ||
// Families are allowed to depend on themselves with different parameters.
(origin.from != null && listenable.from == origin.from) ||
origin.dependencies == null ||
origin.dependencies!.contains(listenable.from) ||
origin.dependencies!.contains(listenable)'
To Reproduce
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'main.g.dart';
@Riverpod(dependencies: [])
class A extends _$A {
@override
Future<String> build() {
return Future.value('A');
}
}
@Riverpod(dependencies: [])
class C extends _$C {
@override
Future<int> build() {
return Future.value(0);
}
}
@Riverpod(dependencies: [C])
class B extends _$B {
@override
Future<bool> build() {
return Future.value(ref.watch(cProvider).valueOrNull == 0);
}
void refresh() {
if (ref.read(cProvider).valueOrNull == 0) {
ref.invalidate(aProvider);
}
}
}
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Consumer(
builder: (context, ref, child) {
final c = ref.watch(cProvider).valueOrNull;
return Text(
'CProvider val ${c ?? 'null'}',
);
},
),
],
),
),
floatingActionButton: Consumer(
builder: (context, ref, child) {
return FloatingActionButton(
onPressed: () {
ref.read(bProvider.notifier).refresh();
},
tooltip: 'Increment',
child: const Icon(Icons.add),
); // Click me
},
),
);
}
}
Expected behavior
provider_dependencies should cover this case.
I tried adding RefInvalidateInvocation to cover this case so I can make a PR if needed:> (thanks to Remi's encapsulation), and I noticed that ref.exists was also missing Invocation.
Should be fixed on dev