Repository: flutter
Issue: [go_router] Redirection with Riverpod example
Labels: d: examples,package,c: proposal,P3,p: go_router,team-go_router,triaged-go_router

This is a request to add an example to the [`go_router`](https://pub.dev/packages/go_router) package that shows how to set up redirection with Riverpod.

## Use case

`go_router` is currently not very well documented and so it took me (as an individual who is familiar with how the different parts of the framework work) quite a while to figure out a solid way to use `go_router` with `flutter_riverpod` properly to handle a **sign-in flow**.

## Proposal

Because of that, I feel like the [existing example catalog](https://github.com/flutter/packages/blob/4bd1dc598aaab5f8179a5429986c36852a54dd63/packages/go_router/example/README.md) should be updated with another sample to complement "Redirection" and "Asynchronous Redirection".  
This is mostly because it works fairly differently under the hood.

---

Is this something you would be willing to integrate into the package? I would also be willing to contribute the example.  
I think this would be very beneficial to also ensure that updates to the package do not break this setup.

***Edit***: sample here [dartpad.dev](https://dartpad.dev/?id=0a77fd6105aeee44858b794e17e83ffc) & explanation here [issuecomment-1269053217](https://github.com/flutter/flutter/issues/112915#issuecomment-1269053217).

### Setup

This method makes use of the fact that reconstructing `GoRouter` will call `redirect` again.  
That means that by providing a `redirect` function that depends on providers, we can both handle calls to `redirect` caused by internal calls (`Navigator.pop`, `context.go`, etc.) as well as the providers updating.

It looks something like this:

```dart
// This is super important - otherwise, we would throw away the whole widget tree when the provider is updated.
final navigatorKey = GlobalKey<NavigatorState>();
// We need to have access to the previous location of the router. Otherwise, we would start from '/' on rebuild.
GoRouter? _previousRouter;

final routerProvider = Provider((ref) {
  final bool loggedIn = ref.watch(loggedInProvider);

  return GoRouter(
    initialLocation: _previousRouter?.location,
    navigatorKey: navigatorKey,
    routes: [...],
    redirect: (context, state) {
      // if the user is not logged in, they need to login
      final bool loggingIn = state.subloc == '/login';
      if (!loggedIn) {
        return loggingIn ? null : '/login';
      }

      // if the user is logged in but still on the login page, send them to
      // the home page
      if (loggingIn) {
        return '/';
      }

      // no need to redirect at all
      return null;
    },
  );
});
```

This setup is so much cleaner and easier to grasp than the [existing Redirection example using `provider`](https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/redirection.dart).

Also note that I was not able to set this up using `refreshListenable`, which is not documented, confusing, and also does not work correctly from what I can tell (it can cause invalid states). Furthermore, the `refreshListenable` setup seems way more hacky than the `riverpod` setup above to begin with.

In conclusion, I think that this method is pretty powerful and I would like to see it included in the package publicly somehow in order to ensure that others can use it and it can be maintained (although it should always work if the package is implemented correctly and checks for equality properly without throwing away the widget tree).