-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[go_router] Add support for preloading branches of StatefulShellRoute #4251
Conversation
Hi, But I have a question (If this is the wrong place for discussions / general questions, please give me a hint on where I can contact you alternatively): As I am having trouble implementing deep linking into our current app structure, I'd like to ask you if it's possible to get StatefulShellRoute working with PageViews? Right now and after searching the web on I might oversee things here, but I guess it's not possible to have a So, instead of having this:
...would something like this also be possible?
This might be obvious for people with more experience on routing, but right now I'm unable to see the forest for the trees...Thank you for your help! |
Hi @JohnnyRainbow81, and thank you! 😊 I did have an example with a PageView at one point, I'll try to find that. I'm also planning on putting together a suite of examples and covering them in a blog post, and they can possibly also be added to flutter/flutter#127209. |
…preload # Conflicts: # packages/go_router/lib/src/builder.dart
This PR is now ready for the first review. As stated in the PR description, there are both similarities and differences compared to the original implementation, most notably that the functionality is concentrated to fewer files (more is handled in ShellRouteBase and StatefulShellRoute). Also, the |
Hi @tolo ! Thanks for answering here :) |
@@ -1,3 +1,7 @@ | |||
## 9.1.0 | |||
|
|||
- Adds preload support to StatefulShellRoute, configurable via `lazy` parameter on StatefulShellBranch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why picking lazy
over preload
? It seems to me latter is more descriptive. I am also a bit concern that lazy may have some negative impression, which we should avoid using in public API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only reason I changed it to lazy was due to suggestions/feedback in #2650, but I agree that perhaps preload is a more fitting name after all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think preload is a more suited name.
// Build pages for preloadable navigators | ||
final Map<GlobalKey<NavigatorState>, RouteMatchList> | ||
preloadableNavigators = | ||
route.preloadableNavigatorLocations(configuration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can all these logic to be done in part of of StatefulNavigationShell
's initState
or didUpdateWidget
or build
? it seems weird that builder would need to know about preload....
We probably need to refactor some API for RouteBuilder though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might, but I'd I have to look in to it, but we would have to expose new API on RouteBuilder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored this logic out of RouteBuilder
, and at the moment into StatefulShellRoute
. The reason I didn't move it into StatefulNavigationShell
and initState
/didUpdateWidget
is that I wanted the call back into RouteBuilder
(buildShellNavigator
) to be in the same build cycle, and thus ensuring the GoRouterStateRegistry
, _PagePopContext
and _goHeroCache
are updated correctly.
(triage) Hi @tolo, are you still planning on coming back to this pr? |
Anything update? This is a good feature for |
(triage) @tolo Is it ok to close this pr for now until you have time to come back to this PR? |
Sorry for the late reply and low activity here recently - been away on a longish summer vacation. I'm planning on finding some time this week to work on this PR, so if we could keep it open for just a while longer, that would be great. |
…preload # Conflicts: # packages/go_router/CHANGELOG.md # packages/go_router/lib/src/builder.dart # packages/go_router/lib/src/route.dart # packages/go_router/lib/src/typedefs.dart # packages/go_router/pubspec.yaml
@chunhtai. Code has been updated. Can you review it? |
Hi @tolo is this ready for another look? |
Yes, I believe it is. |
Is there something we can help to push this feature? |
I have been quite busy lately, I will make sure I review this pr today or tomorrow |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still a bit skeptical about the use case of preload. It seems you can still preload data that is required for rendering ahead of time. The building of the subtree should be fast enough. It may also be cleaner to separate out data model from ui representation anyway. An alternative is to expose api for people to build their own preload solution while keep the statefulShellRoute unopinionated
@@ -1,3 +1,7 @@ | |||
## 9.1.0 | |||
|
|||
- Adds preload support to StatefulShellRoute, configurable via `lazy` parameter on StatefulShellBranch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think preload is a more suited name.
routes: <RouteBase>[ | ||
StatefulShellRoute( | ||
StatefulShellRoute.indexedStack( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why turning this to index stack? this example is for custom stateful_shell_route?
@@ -1157,6 +1241,9 @@ class StatefulNavigationShellState extends State<StatefulNavigationShell> | |||
RouteMatchList? _matchListForBranch(int index) => | |||
_branchLocations[route.branches[index]]?.value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you define a class for both branch and Navigator and use one list to store them, so that you don't need to keep two lists in sync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I think the current API is slightly weird. The navigator will become SizedBox.srink() when they are not loaded but still passed into containerBuilder
, it seems counter intuitive if the containerBuilder
decide to put some child that are never visited before or preloaded before onto the screen. We should probably have a better api.
Another thing is that we rely on both the _preloadNavigator to be build and the containerBuilder
to put it as an offstage child to build the widget subtree. What if they use custom container builder and only builds the child at the index but throw the rest away?
I think the containerBuilder
should have some kind of API that asks child for a given index, and if they do ask for it, we build the complete widget subtree regardless it is preloaded or not.
If branch is set to preload or has been built before but is not built by the containerBuilder, we can build a stack internally by StatefulNavigationShell
and put them offstage
but is not built by the containerBuilder
This will be the hardest part of the implementation, because containerBuilder
can ask for widget build still throw it away. I think you may be able to build some special widget that wraps the navigator and only build subtree when it has not been built before. Not sure if that is a good idea though. Alternative, We could also document that if you ask for widget in containerBuilder
you must also build it in the subtree.
I am curious if there is a better way.
@chunhtai In defense of this PR, I can say that I have been actively using this branch for a month in active project, and it served me well without any problems. My use case is app has two tabs (2 shells of home page), that do network requests to fetch related data. My very first annoyance with the go_router was that the tabs were constantly updated and refetched data as soon as the active tab changed, this was fixed with the help of StatefulShellBranch. The second inconvenience was that when the app was initially launched, the active tab was already making a network request, while the hidden tab was waiting for it to be visible so that network request could be made. This branch's 'preload' thingie fixed that for me. |
@chunhtai Another use case is when a tab registers multiple listeners that are triggered from various locations in the app or in response to remote notification and must react based on those notifications. Listeners are not triggered unless the tab has been loaded. It is not just a matter of pre-fetching data. All what we need is a way for us to be able to pre-load certain tabs. Whether the implementation stays as the current proposal or changed in a way that we can control the loading logic is fine in my opinion. |
Hi @tolo Are you still planning on coming back to this pr? |
Hi @tolo , I am going to close this pr for now, and feel free to reopen if you have time to come back to this pr. |
Is there anyway that we can manually force preloading all branches until this is finalized? Currently we're doing some nasty hacks to visit all branches on app load which is ugly and causes unpleasent UI flickering. |
Hi there, is there any update on this PR? We are also in need of a way to preload all branches. |
@chunhtai The delay is still non negligible compared to a preload even if you load your data before rendering the page, (which we do). Widget tree async builders, images, .. add a delay during the build phase until the page is really ready. The delay is small but noticeable nonetheless |
Sorry for the delay in responding, I'm taking a fresh look at this now. It might be possible to implement this a bit better now, with the refactoring done in However, I see three possible solutions to this:
This is just a brain dump at this stage, but I'm going to start looking at these and see what's possible and makes most sense. |
Surprisingly enough, I believe I was able to re-implement the preload behaviour of this PR, but with substantially less code and complexity. @chunhtai, I guess a new PR would be the best way forward instead of reopening this old one? Anyway, in the meantime, the changes can be found here for anyone interested: |
@johnpryan works on the router I believe |
@tolo In the absence of response, I'd say the best bet would be to open one in the meantime. |
Hey @tolo just a friendly reminder that a new pull request could be posted. Since the review process takes time, might as well post it as early as possible. I can post the PR myself if you do not have the time |
… (revised solution) (#6467) Adds support for preloading branches in a `StatefulShellRoute`. This functionality was initially part of an early implementation of #2650, however it was decided to implement this in a separate PR. The current implementation is a rewrite of the original implementation to better fit the final version of `StatefulShellRoute` (and go_router in general). **NOTE**: this is a revised version of the initial solution (see #4251), containing a substantially simpler implementation made possible thanks to recent refactoring in go_router. This fixes issue flutter/flutter#127804.
Adds support for preloading branches in a
StatefulShellRoute
. This functionality was initially part of an early implementation of #2650, however it was decided to implement this in a separate PR. The current implementation is a rewrite of the original implementation to better fit the final version ofStatefulShellRoute
(and go_router in general).This fixes issue flutter/flutter#127804.
Pre-launch Checklist
dart format
.)[shared_preferences]
pubspec.yaml
with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.md
to add a description of the change, following repository CHANGELOG style.///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.