I'm in the process of migrating my app to use flutter_riverpod
package. At the moment, my app is using provider
package to manage/deal with app state.
I have a lot of static methods inside multiple utility classes that take a BuildContext
as input. I use the context to access the provider, which allows me to read and modify the state:
// This relies on the provider package
abstract class SomeRandomUtilityClass {
static FutureOr<String?> redirect(BuildContext context) {
bool isSignedIn = context.read<AuthProvider>().isSignedIn;
if (!isSignedIn) {
return '/signIn';
} else {
return null;
}
}
How do I achieve this with Riverpod? From what I understand, you need a Ref
to be able to read/write from/to a provider, but I'm not even sure if the APIs allow it.
I tried replacing the BuildContext
parameters of my methods with a Ref
object, but I'm having trouble getting one. All I can access is a WidgetRef
:
class App extends ConsumerWidget {
/** ... **/
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp.router(
/** ... **/
routerConfig: GoRouter(
/** ... **/
routes: [
GoRoute(
/** ... **/
// This doesn't work, because the method I'm calling expects a Ref,
// and not a WidgetRef.
redirect: (_, __) => SomeRandomUtilityClass.redirect(ref),
),
],
),
);
}
}
An easy fix would be to modify my static methods by changing the type of the parameter from Ref
to WidgetRef
, but the maintainer of the Riverpod package says that passing WidgetRef
s is a bad idea.
I might be misunderstanding something. Please let me know if I am.
As you stated, yes, WidgetRef
and Ref
are of two different types, thus the error.
To understand why, consider that this: passing WidgetRef
is a bad idea because WidgetRef
s are (indeed) linked their Widget
's element. Their life cycle are indeed tied to the life cycle of a widget, whereas the lifecycle of a provider is a different thing. In a certain way, WidgetRef
is closer to an AutoDisposeRef
.
But passing around WidgetRef
s around would be dangerous since you could technically mark widgets as dirty in a way that's not meant to be with Riverpod.
Long story short, in general, there's a good chance you want to refactor static methods into a single simple provider, which is, in the end, just a function with a ref
wrapper on it.
I'd highly suggest using riverpod_annotation
, too. You'd save time and you'd obtain something very readable and concise (and hassle-free):
@riverpod
T yourFunction(YourFunctionRef ref) {
final someValue = ref.watch(someDependencyProvider);
// logic
return someComputedValue; // Type T
}
In your specific use case, though, you're trying to implement a redirect with go router and riverpod. I'd avoid creating a simple provider like that, since it would cause the root of your app to rebuild on auth change.
That's a "deep" topic, and there are several way to do so; I've created a repo here just to show off how to work around this. It's a 3rd party riverpod examples repo.
Check the complete_example
folder, there for a full example, or search for older and simpler examples in other folders.