Skip to content

[go_router] Navigating back from a sub-route to the parent route does not call "redirect" #145173

@elia-ba

Description

@elia-ba

Steps to reproduce

  1. Run this gist: https://dartpad.dev/?id=fbfa675230ed6e129f45ee7c22665a44
  2. Tap /bar/baz, redirect is called and stays on /foo
  3. Toggle on the switch at the bottom so it's on
  4. Tap /bar/baz again, redirect is called and navigation works fine
  5. Toggle on the switch at the bottom so it's off
  6. Navigate back
  7. You can navigate fine, redirect is NOT called

Expected results

redirect should always be called when navigating to a different route.

Actual results

redirect is not called when navigating back to parent route from child route.

Note that this is the same as reported in #101183
That issue was closed as merged but this problem persists.

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() => runApp(const AllowedWidget(child: MyApp()));

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late final GoRouter _router;

  @override
  void dispose() {
    _router.dispose();
    super.dispose();
  }

  @override
  Widget build(context) {
    final allow = InheritedAllowedWidget.of(context).notifier;
    _router = GoRouter(
      routes: <GoRoute>[
        GoRoute(path: '/', redirect: (BuildContext context, GoRouterState state) => '/foo'),
        GoRoute(
          path: '/foo',
          builder: (context, state) => MyPage(
            key: state.pageKey,
            nexts: const ['/bar', '/bar/baz'],
          ),
        ),
        GoRoute(
          path: '/bar',
          builder: (context, state) => MyPage(
            key: state.pageKey,
            nexts: const ['/bar/baz'],
          ),
          routes: [
            GoRoute(
              path: 'baz',
              builder: (context, state) => MyPage(
                key: state.pageKey,
                nexts: const ['/foo'],
              ),
            ),
          ],
        ),
      ],
      redirect: (BuildContext context, GoRouterState state) {
        print('redirect called');
        return allow.value ? null : '/foo';
        },
    );
    return MaterialApp.router(
      routeInformationProvider: _router.routeInformationProvider,
      routeInformationParser: _router.routeInformationParser,
      routerDelegate: _router.routerDelegate,
    );
  }
}

class MyPage extends StatelessWidget {
  final Iterable<String> nexts;
  const MyPage({
    required this.nexts,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(context) {
    final allow = InheritedAllowedWidget.of(context).notifier;
    return Scaffold(
      appBar: AppBar(
        title: Text(GoRouter.of(context).routerDelegate.currentConfiguration.uri.toString()),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          for (final next in nexts)
            Center(
              child: TextButton(
                child: Text(next),
                onPressed: () => context.go(next),
              ),
            ),
          Center(
            child: ValueListenableBuilder<bool>(
              valueListenable: allow,
              builder: (context, allowed, _) => Switch(
                value: allowed,
                onChanged: (value) => allow.value = value,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class InheritedAllowedWidget extends InheritedWidget {
  const InheritedAllowedWidget({
    Key? key,
    required this.notifier,
    required Widget child,
  }) : super(
          key: key,
          child: child,
        );

  final ValueNotifier<bool> notifier;

  static InheritedAllowedWidget of(BuildContext context) {
    final InheritedAllowedWidget? result =
        context.dependOnInheritedWidgetOfExactType<InheritedAllowedWidget>();
    assert(result != null, 'No InheritedAllowedWidget found in context');
    return result!;
  }

  @override
  bool updateShouldNotify(InheritedAllowedWidget oldWidget) =>
      notifier.hashCode != oldWidget.notifier.hashCode;
}

class AllowedWidget extends StatefulWidget {
  final Widget child;
  const AllowedWidget({
    required this.child,
    Key? key,
  }) : super(key: key);

  @override
  State<AllowedWidget> createState() => _AllowedWidgetState();
}

class _AllowedWidgetState extends State<AllowedWidget> {
  late final ValueNotifier<bool> _notifier;

  @override
  void initState() {
    _notifier = ValueNotifier(false);
    super.initState();
  }

  @override
  void dispose() {
    _notifier.dispose();
    super.dispose();
  }

  @override
  Widget build(context) => InheritedAllowedWidget(
        notifier: _notifier,
        child: widget.child,
      );
}

Screenshots or Video

Screenshots / Video demonstration

Logs

Logs

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.16.9, on Ubuntu 20.04.1 LTS 5.8.18-050818-generic, locale en_IE.UTF-8)
    • Flutter version 3.16.9 on channel stable at /media/sw/sdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 41456452f2 (7 weeks ago), 2024-01-25 10:06:23 -0800
    • Engine revision f40e976bed
    • Dart version 3.2.6
    • DevTools version 2.28.5

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /media/sw/sdk/Android/sdk
    • Platform android-34, build-tools 33.0.1
    • ANDROID_HOME = /media/sw/sdk/Android/sdk
    • ANDROID_SDK_ROOT = /media/sw/sdk/Android/sdk
    • Java binary at: /media/sw/sdk/android-studio/jbr/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 10.0.0-4ubuntu1
    • cmake version 3.18.3
    • ninja version 1.10.0
    • pkg-config version 0.29.1

[✓] Android Studio (version 2022.1)
    • Android Studio at /media/sw/sdk/android-studio
    • Flutter plugin version 72.0.2
    • Dart plugin version 221.6096
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-8887301)

[✓] VS Code (version 1.86.1)
    • VS Code at /usr/share/code
    • Flutter extension version 3.84.0

[✓] Connected device (3 available)
    • RMO NX1 (mobile) • LLL • android-arm64  • Android 13 (API 33)
    • Linux (desktop)  • linux            • linux-x64      • Ubuntu 20.04.1 LTS 5.8.18-050818-generic
    • Chrome (web)     • chrome           • web-javascript • Google Chrome 109.0.5414.119

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    r: duplicateIssue is closed as a duplicate of an existing issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions