Repository: flutter
Issue: [go_router] triggering a pop and a redirect (that returns null) causes a route to reopen
Labels: package,has reproducible steps,P2,p: go_router,team-go_router,triaged-go_router,found in release: 3.16,found in release: 3.18

### Steps to reproduce

1. hit navigate button
2. hit pop button

### Expected results

the route pops despite the triggered redirect

### Actual results

the route is not popped

### Code sample

<details open><summary>Code sample</summary>

```dart
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() => runApp(App());

class InheritedUser extends InheritedWidget {
  const InheritedUser({
    required this.isLoggedIn,
    required this.counter,
    required super.child,
    super.key,
  });

  final bool isLoggedIn;
  final int counter;

  static InheritedUser of(BuildContext context) =>
      context.dependOnInheritedWidgetOfExactType<InheritedUser>()!;

  @override
  bool updateShouldNotify(InheritedUser oldWidget) =>
      isLoggedIn != oldWidget.isLoggedIn || counter != oldWidget.counter;
}

class InheritedUserMutator extends StatefulWidget {
  const InheritedUserMutator({super.key, required this.child});

  final Widget child;

  @override
  State<InheritedUserMutator> createState() => _InheritedUserMutatorState();
}

class _InheritedUserMutatorState extends State<InheritedUserMutator> {
  bool _isLoggedIn = false;
  int _counter = 0;

  void setLoggedInStatus(bool isLoggedIn) {
    _isLoggedIn = isLoggedIn;
    setState(() {});
  }

  void doSomeOtherUpdate() {
    _counter++;

    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return InheritedUser(
      isLoggedIn: _isLoggedIn,
      counter: _counter,
      child: widget.child,
    );
  }
}

/// The main app.
class App extends StatelessWidget {
  /// Creates an [App].
  App({super.key});

  /// The title of the app.
  static const String title = 'GoRouter Example: Redirection';

  // add the login info into the tree as app state that can change over time
  @override
  Widget build(BuildContext context) => InheritedUserMutator(
        child: MaterialApp.router(
          routerConfig: _router,
          title: title,
          debugShowCheckedModeBanner: false,
        ),
      );

  late final GoRouter _router = GoRouter(
    initialLocation: '/',
    routes: <GoRoute>[
      GoRoute(
        path: '/home',
        builder: (BuildContext context, GoRouterState state) =>
            const HomeScreen(),
      ),
      GoRoute(
        path: '/login',
        builder: (BuildContext context, GoRouterState state) =>
            const LoginScreen(),
        routes: <RouteBase>[
          GoRoute(
            path: 'home_popup_route',
            builder: (_, __) => const HomePopupRoute(),
          ),
        ],
      ),
    ],

    // redirect to the login page if the user is not logged in
    redirect: (BuildContext context, GoRouterState state) {
      // if the user is not logged in, they need to login
      final bool loggedIn = InheritedUser.of(context).isLoggedIn;
      final bool loggingIn = state.matchedLocation.startsWith('/login');

      if (!loggedIn && loggingIn) {
        return null;
      }

      if (!loggedIn) {
        return '/login';
      }

      // if the user is logged in but still on the login page, send them to
      // the home page
      if (loggingIn) {
        return '/home';
      }

      // no need to redirect at all
      return null;
    },

    // changes on the listenable will cause the router to refresh it's route
    debugLogDiagnostics: true,
  );
}

/// The login screen.
class LoginScreen extends StatelessWidget {
  /// Creates a [LoginScreen].
  const LoginScreen({super.key});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text(App.title)),
        body: Center(
          child: Column(
            children: <Widget>[
              ElevatedButton(
                onPressed: () {
                  context
                      .findAncestorStateOfType<_InheritedUserMutatorState>()!
                      .setLoggedInStatus(true);
                },
                child: const Text('Login'),
              ),
              ElevatedButton(
                onPressed: () {
                  context.push('/login/home_popup_route');
                },
                child: const Text('Navigate'),
              ),
              Text(GoRouterState.of(context).fullPath ?? '')
            ],
          ),
        ),
      );
}

/// The home screen.
class HomeScreen extends StatelessWidget {
  /// Creates a [HomeScreen].
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(App.title),
        actions: <Widget>[
          IconButton(
            onPressed: () => context
                .findAncestorStateOfType<_InheritedUserMutatorState>()!
                .setLoggedInStatus(false),
            tooltip: 'Logout:',
            icon: const Icon(Icons.logout),
          )
        ],
      ),
      body: const Center(
        child: Text('HomeScreen'),
      ),
    );
  }
}

class HomePopupRoute extends StatelessWidget {
  const HomePopupRoute({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          TextButton(
            onPressed: () async {
              context
                  .findAncestorStateOfType<_InheritedUserMutatorState>()!
                  .doSomeOtherUpdate();

              context.pop(true);
            },
            child: const Text('Pop'),
          )
        ],
      ),
      body: const Center(
        child: Text('HomeScreen'),
      ),
    );
  }
}

```

</details>


### Screenshots or Video

<details open>
<summary>Screenshots / Video demonstration</summary>

https://github.com/flutter/flutter/assets/40719830/5a7636a3-aa3a-4d00-ba3e-47e2aff33aa2

</details>


### Logs

<details open><summary>Logs</summary>

```console
Launching lib/main.dart on sdk gphone64 arm64 in debug mode...
✓  Built build/app/outputs/flutter-apk/app-debug.apk.
Connecting to VM Service at ws://127.0.0.1:56745/KNJkTiWcLvY=/ws
[GoRouter] Full paths for routes:
             => /home
             => /login
             =>   /login/home_popup_route
[GoRouter] setting initial location /
[GoRouter] No initial matches: /
[GoRouter] redirecting to RouteMatchList(/login)
[GoRouter] Using MaterialApp configuration
W/Parcel  ( 9200): Expecting binder but got null!
[GoRouter] pushing /login/home_popup_route
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=83748.22ms min=171.92ms max=167324.52ms count=2
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=29.22ms min=0.93ms max=609.39ms count=25
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=22.87ms min=1.21ms max=459.58ms count=33
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=22.71ms min=9.49ms max=209.79ms count=44
D/EGL_emulation( 9200): app_time_stats: avg=23.78ms min=1.13ms max=479.28ms count=34
D/EGL_emulation( 9200): app_time_stats: avg=9882.42ms min=1.84ms max=39523.18ms count=4
[GoRouter] pushing /login/home_popup_route
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=67.67ms min=2.32ms max=990.84ms count=20
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=23.78ms min=1.13ms max=509.49ms count=38
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=29.52ms min=9.78ms max=440.26ms count=34
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/EGL_emulation( 9200): app_time_stats: avg=27.52ms min=11.51ms max=404.93ms count=37
[GoRouter] popping /login
W/OnBackInvokedCallback( 9200): OnBackInvokedCallback is not enabled for the application.
W/OnBackInvokedCallback( 9200): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
```

</details>


### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.16.2, on macOS 13.2.1 22D68 darwin-arm64, locale en-UZ)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.3)
[✓] VS Code (version 1.85.1)
[✓] Connected device (4 available)
    ! Error: Alex’s phone is busy: Waiting to connect and unlock the device. Xcode will continue when Alex’s phone is
      finished. (code -10)
[✓] Network resources
```

</details>