-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Fix: Router white flash on first navigation to page #3772
Conversation
@Tobbe I checked-out this locally, this is a neat solution! But I'm afraid unmounting could still happen if navigation is not between the <Router>
<Set wrap={TestWrapper}>
<Route path="/second" page={SecondPage} name="second" />
</Set>
<Route path="/first" page={FirstPage} name="first" />
<Route notfound page={NotFoundPage} />
</Router> From what I understood, if it was only possible to wrap Set once, even we could have handled it with simple control flow but Set could be multi-level nested. Can we somehow retain the route state even if parents change? |
Yes, I considered this too. Here's what I'm afraid will happen if we have a "global" Page. But I haven't fully verified. The PageLoader is only for the actual page, not the Set and the wrappers around it. |
You're right, that would be a very inconsistent state. Worse than the white screen IMO.
I see the white page for this case, am I missing something here? |
Sorry, English is difficult... I just meant I knew about the scenario you mentioned. And that I thought the white flash was better than the alternative I described. |
Oh, I see. Would love to know your thought on this: #3767 (comment)
Having PageLoader outside will hold the "swapping" process (including Sets) until the page is ready. What do you think? Too much change? |
737863d
to
e3e5951
Compare
I felt I couldn't get a good grip on how much work this would be, so I just got started on it. And it doesn't look like it'll be too bad. I'll spend a few hours more on it tomorrow to finish it off. |
7831b05
to
49f0077
Compare
Hah! That wasn't true. This turned out to be a much bigger and complicated change than I first thought. @jtoar This touches on the a11y stuff you've built. Had to update the Set test snapshots. Can you please take a look? |
Prerender tests are pretty solid! |
Awesome! That's a relief 🙂 |
@callingmedic911 I'd love your review of this 🙏 |
Glad to. Huge props to you for pulling this big of a change this fast. 🙌 🚀 I'll try to squeeze some time this weekend to review. |
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.
Awesome job @Tobbe! This one's a doozy. I'll have to take more than one pass at reviewing it.
First off, super happy that ActiveRouteLoader
is a function component! When I was digging into React 18 I was worried that it might take a lot of nontrivial work to get the Router concurrent-mode/suspense ready. There's still some work to do but I'm feeling a lot better about it now that it's a function component.
I've tried this PR out locally on an app I have. The behavior's definitely fixed, and I haven't caught any regressions yet.
After this PR, I think we need to take some time to organize some of the code in the router package. For example, path-validation logic seems to be duplicated in a few places; it'd be easier to follow if it was centralized. Moreover, we need a legit "understanding the router" or contributing guide.
if (global.__REDWOOD__PRERENDERING) { | ||
// babel auto-loader plugin uses withStaticImport in prerender mode | ||
// override the types for this condition | ||
const syncPageLoader = spec.loader as unknown as synchronousLoaderSpec | ||
const PageFromLoader = syncPageLoader().default | ||
|
||
const prerenderLoadingState: LoadingStateRecord = { | ||
[path]: { | ||
state: 'DONE', | ||
page: PageFromLoader, | ||
}, | ||
} |
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's tempting to want to move this up and "return early", but (I think) it actually needs to be here because we can't call hooks conditionally. That's all just to say that it may be worth adding a comment here explaining why it's last.
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.
Done. Please lmk what you think
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.
@jtoar Have you had a chance to look at this yet?
15b1a3a
to
e20e26b
Compare
|
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.
This looks good to go! I feel like this really opens the door to even more refactoring, like you brought up in your page loader issue (I think we could consolidate “validatePaths” too—I’ll make a few follow-up issues myself).
I’m really impressed by all the work you did with the router tests. I thought that we might have to be perennially on-the-look-out for the flash, but you’ve seriously tested it every which way. I’ll try to take a page out of your book when writing tests going forward.
I’ll leave you to merge 🚀
0ffc1df
to
3d6610b
Compare
This is an alternative attempt at a solution for #2124
When I was reviewing @callingmedic911's PR for the same issue (#3767) I did some refactoring while getting myself up-to-speed on the code again. And while doing so (and after reading @jtoar's excellent link to the React beta docs) I came up with a (in my eyes) simpler solution to the problem.
This PR has two commits (as of writing this). The first one is just the refactoring I did. The second one is the actual solution to the linked issue.
The TL;DR of it is: Set a hard-coded
key
on the<Route>
s so that<PageLoader>
can keep its state while navigating.Need to update the docs: https://redwoodjs.com/docs/prerender#flash-after-page-load