csells / go_router

The purpose of the go_router for Flutter is to use declarative routes to reduce complexity, regardless of the platform you're targeting (mobile, web, desktop), handling deep linking from Android, iOS and the web while still allowing an easy-to-use developer experience.
https://gorouter.dev
441 stars 97 forks source link

Push route on 404 error builder doesn't work #143

Closed jaumard closed 3 years ago

jaumard commented 3 years ago

I'm trying to do a 404 page not found screen with a button to return to the website:

errorPageBuilder: (BuildContext context, GoRouterState state) {
        return CustomTransitionPage<void>(
          key: state.pageKey,
          transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
            return FadeTransition(opacity: animation, child: child);
          },
          child: BgContainer(
            child: IntroDialog(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text('404 page introuvable', style: context.textTheme.headline6),
                  const SizedBox(height: kSmallPadding),
                  TextButton(
                    onPressed: () {
                      context.go('/');
                    },
                    child: const Text('Retourner sur le site'),
                  ),
                ],
              ),
            ),
          ),
        );

When I click I get:

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Assertion failed: file:///Users/jaumard/.pub-cache/hosted/pub.dartlang.org/go_router-2.2.4/lib/src/go_router.dart:123:12
inherited != null
"No GoRouter found in context"

When the exception was thrown, this was the stack: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49  throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3    assertFailed
packages/go_router/src/go_router.dart 123:21                                  of
packages/go_router/go_router.dart 32:25                                       GoRouterHelper.go
packages/heal_happy/common/router.dart 121:31                                 <fn>
packages/flutter/src/material/ink_well.dart 989:21                            [_handleTap]
packages/flutter/src/gestures/recognizer.dart 193:24                          invokeCallback
packages/flutter/src/gestures/tap.dart 608:48                                 handleTapUp
packages/flutter/src/gestures/tap.dart 296:5                                  [_checkUp]
packages/flutter/src/gestures/tap.dart 230:7                                  handlePrimaryPointer
packages/flutter/src/gestures/recognizer.dart 558:9                           handleEvent
packages/flutter/src/gestures/pointer_router.dart 94:12                       [_dispatch]
packages/flutter/src/gestures/pointer_router.dart 139:9                       <fn>
dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13      forEach
packages/flutter/src/gestures/pointer_router.dart 137:17                      [_dispatchEventToRoutes]
packages/flutter/src/gestures/pointer_router.dart 123:7                       route
packages/flutter/src/gestures/binding.dart 440:19                             handleEvent
packages/flutter/src/gestures/binding.dart 420:14                             dispatchEvent
packages/flutter/src/rendering/binding.dart 278:11                            dispatchEvent
packages/flutter/src/gestures/binding.dart 374:7                              [_handlePointerEventImmediately]
packages/flutter/src/gestures/binding.dart 338:5                              handlePointerEvent
packages/flutter/src/gestures/binding.dart 296:7                              [_flushPointerEventQueue]
packages/flutter/src/gestures/binding.dart 279:32                             [_handlePointerDataPacket]
lib/_engine/engine/platform_dispatcher.dart 1018:13                           invoke1
lib/_engine/engine/platform_dispatcher.dart 182:5                             invokeOnPointerDataPacket
lib/_engine/engine/pointer_binding.dart 130:39                                [_onPointerData]
lib/_engine/engine/pointer_binding.dart 555:18                                <fn>
lib/_engine/engine/pointer_binding.dart 508:21                                <fn>
lib/_engine/engine/pointer_binding.dart 216:16                                loggedHandler
Handler: "onTap"
Recognizer: TapGestureRecognizer#a3ce4
  debugOwner: GestureDetector
  state: ready
====================================================================================================

Look like router is not accessible from the context given to the error callback :/ did I miss something ?

I use version 2.2.1 on last flutter stable

csells commented 3 years ago

That's a standard Flutter issue. Assuming the following:

late final router = GoRouter(...);

then you can do the following:

onPressed: () => router.go(...);

Does that work for you?

P.S. don't for the late keyword!

jaumard commented 3 years ago

So I need a global variable to avoid this? It will works for sure but that's ugly :D

csells commented 3 years ago

100% not. You can continue to define your router inside your app, e.g.

class MyApp {
  ...
  late final router = GoRouter(...);
  ...
}
jaumard commented 3 years ago

Yeah I put the router creation inside his own file ^^, something like this:


late GoRouter _router;

GoRouter createRouter(UserStore userStore) => _router = GoRouter(
      //... all routes and redirection stuff
      errorPageBuilder: (BuildContext context, GoRouterState state) {
        return CustomTransitionPage<void>(
          key: state.pageKey,
          transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
            return FadeTransition(opacity: animation, child: child);
          },
          child: BgContainer(
            child: IntroDialog(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text('404 page introuvable', style: context.textTheme.headline6),
                  const SizedBox(height: kSmallPadding),
                  TextButton(
                    onPressed: () {
                      _router.go('/');
                    },
                    child: const Text('Retourner sur le site'),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );

I have added the global variable (as private) and no more issues like this.

csells commented 3 years ago

Cool.