简体   繁体   中英

flutter_riverpod - Accessing a `Ref` when `context` is available

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM