Skip to content

[go_router] Remove dependency looks up in GoRouter.of to reduce unwanted rebuild #123570

@Andrious

Description

@Andrious

I'm seeing an odd curiosity when I try out GoRouter.
I suspect it's actually by design, but I'm not sure, so I'm here to clarify this.

flutter doctor -v
[√] Flutter (Channel stable, 3.7.8, on Microsoft Windows [Version 10.0.22621.1413], locale en-CA)
    • Flutter version 3.7.8 on channel stable at C:\Programs\Tools\flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 90c64ed42b (6 days ago), 2023-03-21 11:27:08 -0500
    • Engine revision 9aa7816315
    • Dart version 2.19.5
    • DevTools version 2.20.1

[√] Windows Version (Installed version of Windows is version 10 or higher)


[√] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at C:\Programs\Tools\Android\SDK
    • Platform android-33, build-tools 33.0.0
    • ANDROID_HOME = C:\Programs\Tools\Android\SDK
    • ANDROID_SDK_ROOT = C:\Programs\Tools\Android\SDK
    • Java binary at: C:\Programs\Tools\Android\Studio\jbr\bin\java
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-9505619)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe

[X] Visual Studio - develop for Windows
    X Visual Studio not installed; this is necessary for Windows development.
      Download at https://visualstudio.microsoft.com/downloads/.
      Please install the "Desktop development with C++" workload, including all of its default components

[√] Android Studio (version 2022.1)
    • Android Studio at C:\Programs\Tools\Android\Studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.15+0-b2043.56-9505619)

[√] IntelliJ IDEA Community Edition (version 2019.1)
    • IntelliJ at C:\Programs\Tools\Dart\IntelliJ
    • Flutter plugin version 35.0.3
    • Dart plugin version 191.7019

[√] Connected device (5 available)
    • ONEPLUS A5010 (mobile)           • c6a80e66      • android-arm64  • Android 10 (API 29)
    • sdk gphone x86 64 arm64 (mobile) • emulator-5554 • android-x64    • Android 11 (API 30) (emulator)
    • Windows (desktop)                • windows       • windows-x64    • Microsoft Windows [Version 10.0.22621.1413]     
    • Chrome (web)                     • chrome        • web-javascript • Google Chrome 111.0.5563.111
    • Edge (web)                       • edge          • web-javascript • Microsoft Edge 111.0.1661.41

[√] HTTP Host Availability
    • All required HTTP hosts are available

! Doctor found issues in 1 category.

Steps to Reproduce

Download the little demo app from this repo.

Tap on the graphic below to see a gif file displaying the demo app in action.

It's made up of nine State classes. One is called after the other.
Each has buttons so you can go back and forth between them.

image

The first link below is of my console recording what State objects are built when tapping up to Page 3 in the Demo app:
Up to Page 3

It makes sense, I guess.
It's recursively building all the State object up to the most recent one.
For example, pushing to page 3, the home page, page 1, and page 2 have their build functions called as well.
Guess it's part of sustaining the 'deep link' URL feature particularly desired by web apps.

However, as you progress through the screens in the little demo app, you'll see a different pattern come about.
It's not calling all the build functions from the State objects that proceeded anymore. It still 'rebuilds' the previous State object the router just left, but not before calling the build() functions of 'Page 1' and the 'Home' page:
Up to Page 9

Did you see the pattern in the screenshot above?
Why, with every new route, the last state object is always built again?
Why are the first two State objects in the series always rebuilt again as well??

The sample code is merely how the GoRouter class was set up. The full source code is in the repo.

Sample code
 MaterialApp.router(
        title: 'Demo App',
        routerConfig: GoRouter(
          observers: [StateXRouteObserver.routeObserver!],
          routes: <RouteBase>[
            GoRoute(
              path: '/',
              builder: (BuildContext context, GoRouterState state) {
                return const HomePage();
              },
            ),
            GoRoute(
              path: '/page1',
              builder: (BuildContext context, GoRouterState state) {
                return const Page1();
              },
            ),
            GoRoute(
              path: '/page2',
              builder: (BuildContext context, GoRouterState state) {
                return const Page2();
              },
            ),
            GoRoute(
              path: '/page3',
              builder: (BuildContext context, GoRouterState state) {
                return const Page3();
              },
            ),
            GoRoute(
              path: '/page4',
              builder: (BuildContext context, GoRouterState state) {
                return const Page4();
              },
            ),
            GoRoute(
              path: '/page5',
              builder: (BuildContext context, GoRouterState state) {
                return const Page5();
              },
            ),
            GoRoute(
              path: '/page6',
              builder: (BuildContext context, GoRouterState state) {
                return const Page6();
              },
            ),
            GoRoute(
              path: '/page7',
              builder: (BuildContext context, GoRouterState state) {
                return const Page7();
              },
            ),
            GoRoute(
              path: '/page8',
              builder: (BuildContext context, GoRouterState state) {
                return const Page8();
              },
            ),
            GoRoute(
              path: '/page9',
              builder: (BuildContext context, GoRouterState state) {
                return const Page9();
              },
            ),
          ],
          debugLogDiagnostics: true,
        ),
      );
Console
Launching lib\main.dart on sdk gphone x86 64 arm64 in debug mode...
Running Gradle task 'assembleDebug'...
√  Built build\app\outputs\flutter-apk\app-debug.apk.
Installing build\app\outputs\flutter-apk\app-debug.apk...
Debug service listening on ws://127.0.0.1:51290/PcNG7dN7-84=/ws
Syncing files to device sdk gphone x86 64 arm64...
[GoRouter] Full paths for routes:
  => /
  => /page1
  => /page2
  => /page3
  => /page4
  => /page5
  => /page6
  => /page7
  => /page8
  => /page9

[GoRouter] setting initial location null
[GoRouter] Using MaterialApp configuration
I/flutter (14264): ###########  build() in HomePage
[GoRouter] pushing /page1
I/flutter (14264): ###########  initState() in _Page1State#06558(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page1State#06558(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
[GoRouter] pushing /page2
I/flutter (14264): ###########  didPushNext() in _Page1State#06558
I/flutter (14264): ###########  initState() in _Page2State#91bee(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page2State#91bee(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page2State#91bee   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
[GoRouter] pushing /page3
I/flutter (14264): ###########  didPushNext() in _Page2State#91bee
I/flutter (14264): ###########  initState() in _Page3State#56793(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page3State#56793(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page3State#56793   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page2State#91bee   counter: 0
[GoRouter] pushing /page4
I/flutter (14264): ###########  didPushNext() in _Page3State#56793
I/flutter (14264): ###########  initState() in _Page4State#c2bff(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page4State#c2bff(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page4State#c2bff   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page3State#56793   counter: 0
[GoRouter] pushing /page5
I/flutter (14264): ###########  didPushNext() in _Page4State#c2bff
I/flutter (14264): ###########  initState() in _Page5State#ff6fa(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page5State#ff6fa(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page5State#ff6fa   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page4State#c2bff   counter: 0
[GoRouter] pushing /page6
I/flutter (14264): ###########  didPushNext() in _Page5State#ff6fa
I/flutter (14264): ###########  initState() in _Page6State#e264c(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page6State#e264c(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page6State#e264c   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page5State#ff6fa   counter: 0
[GoRouter] pushing /page7
I/flutter (14264): ###########  didPushNext() in _Page6State#e264c
I/flutter (14264): ###########  initState() in _Page7State#478c5(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page7State#478c5(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page7State#478c5   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page6State#e264c   counter: 0
[GoRouter] pushing /page8
I/flutter (14264): ###########  didPushNext() in _Page7State#478c5
I/flutter (14264): ###########  initState() in _Page8State#47b7f(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page8State#47b7f(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page8State#47b7f   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page7State#478c5   counter: 0
[GoRouter] pushing /page9
I/flutter (14264): ###########  didPushNext() in _Page8State#47b7f
I/flutter (14264): ###########  initState() in _Page9State#55102(lifecycle state: created)
I/flutter (14264): ###########  didPush() in _Page9State#55102(lifecycle state: initialized)
I/flutter (14264): ###########  build() in _Page9State#55102   counter: 0
I/flutter (14264): ###########  build() in _Page1State#06558   counter: 0
I/flutter (14264): ###########  build() in HomePage
I/flutter (14264): ###########  build() in _Page8State#47b7f   counter: 0

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listfound in release: 3.7Found to occur in 3.7found in release: 3.9Found to occur in 3.9has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: go_routerThe go_router packagepackageflutter/packages repository. See also p: labels.r: fixedIssue is closed as already fixed in a newer version

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions