-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Implement new client-side router #37551
Merged
kodiakhq
merged 108 commits into
vercel:canary
from
timneutkens:add/back-nav-optimization-2
Jul 6, 2022
Merged
Implement new client-side router #37551
kodiakhq
merged 108 commits into
vercel:canary
from
timneutkens:add/back-nav-optimization-2
Jul 6, 2022
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
- Handle back/forward navigation - Only render down from the common layout Co-Authored-By: Sebastian Markbåge <[email protected]>
timneutkens
requested review from
ijjk,
shuding,
padmaia and
huozhi
as code owners
June 19, 2022 19:29
# Conflicts: # test/integration/react-server-components/test/index.test.js
ijjk
approved these changes
Jul 6, 2022
kodiakhq bot
pushed a commit
that referenced
this pull request
Jul 7, 2022
- Remove cache value that was incorrectly nested deeper - Remove extra useEffect (already applied during hydration based on the `useReducer` input) - Add dynamic parameter name into the tree Follow-up to #37551, cleans up some code and prepares for catch-all and optional catch-all routes.
kodiakhq bot
pushed a commit
that referenced
this pull request
Jul 7, 2022
This outputs a separate manifest for leveraging during deploy to handle the new app outputs. Also ensures dynamic routes from `app` our output in the `routes-manifest` correctly along with fixing the `react-dom` import. x-ref: #37551
11 tasks
kodiakhq bot
pushed a commit
that referenced
this pull request
Jul 8, 2022
Adds support for `[...slug]` dynamic segments. I found there's an inconsistency in query/params providing and added a quick fix for it now. Will update the handling in a follow-up PR to ensure it's consistently providing dynamic params outside of `query`. Follow-up of #37551 and #38415. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples)
Awesome work guys, thanks! |
This was referenced Jul 13, 2022
timneutkens
added a commit
to timneutkens/next.js
that referenced
this pull request
Jul 14, 2022
Follow-up to vercel#37551. Implements scrolling into view and moving focus to the changed part of the page. In order to achieve this we need to have a ref to a DOM node which currently means that the layout-router will wrap it's content into a `div`, this might be removed in the future when React has APIs for selecting elements similar to https://reactjs.org/docs/react-dom.html#finddomnode
3 tasks
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Client-side router for
app
directoryThis PR implements the new router that leverages React 18 concurrent features like Suspense and startTransition.
It also integrates with React Server Components and builds on top of it to allow server-centric routing that only renders the part of the page that has to change.
It's one of the pieces of the implementation for https://nextjs.org/blog/layouts-rfc.
Details
I'm going to document the differences with the current router here (will be reworked for the upgrade guide)
Client-side cache
In the current router we have an in-memory cache for getStaticProps data so that if you prefetch and then navigate to a route that has been prefetched it'll be near-instant. For getServerSideProps the behavior is different, any navigation to a page with getServerSideProps fetches the data again.
In the new model the cache is a fundamental piece, it's more granular than at the page level and is set up to ensure consistency across concurrent renders. It can also be invalidated at any level.
Push/Replace (also applies to next/link)
The new router still has a
router.push
/router.replace
method.There are a few differences in how it works though:
href
as an argument, historically you had to providehref
(the page path) andas
(the actual url path) to do dynamic routing. In later versions of Next.js this is no longer required and in the majority of casesas
was no longer needed. In the new router there's no way to reason abouthref
vsas
because there is no notion of "pages" in the browser.startTransition
, you can wrap these in your ownstartTransition
to getisPending
Hard/Soft push/replace
Because of the client-side cache being reworked this now allows us to cover two cases: hard push and soft push.
The main difference between the two is if the cache is reused while navigating. The default for
next/link
is ahard
push which means that the part of the cache affected by the navigation will be invalidated, e.g. if you already navigated to/dashboard
and yourouter.push('/dashboard')
again it'll get the latest version. This is similar to the existinggetServerSideProps
handling.In case of a soft push (API to be defined but for testing added
router.softPush('/')
) it'll reuse the existing cache and not invalidate parts that are already filled in. In practice this means it's more like thegetStaticProps
client-side navigation because it does not fetch on navigation except if a part of the page is missing.Back/Forward navigation
Back and Forward navigation (popstate) are always handled as a soft navigation, meaning that the cache is reused, this ensures back/forward navigation is near-instant when it's in the client-side cache. This will also allow back/forward navigation to be a high priority update instead of a transition as it is based on user interaction. Note: in this PR it still uses
startTransition
as there's no way to handle the high priority update suspending which happens in case of missing data in the cache. We're working with the React team on a solution for this particular case.Layouts
Note: this section assumes you've read The layouts RFC and React Server Components RFC
React Server Components rendering leverages the Flight streaming mechanism in React 18, this allows sending a serializable representation of the rendered React tree on the server to the browser, the client-side React can use this serialized representation to render components client-side without the JavaScript being sent to the browser. This is one of the building blocks of Server Components. This allows a bunch of interesting features but for now I'll keep it to how it affects layouts.
When you have a
app/dashboard/layout.js
andapp/dashboard/page.js
the page will render as children of the layout, when you add another page likeapp/dashboard/integrations/page.js
that page falls under the dashboard layout as well. When client-side navigating the new router automatically figures out if the page you're navigating to can be a smaller render than the whole page, in this caseapp/dashboard/page.js
andapp/dashboard/integrations/page.js
share theapp/dashboard/layout.js
so instead of rendering the whole page we render below the layout component, this means the layout itself does not get re-rendered, the layout'sgetServerSideProps
would not be called, and the Flight response would only hold the result ofapp/dashboard/integrations/page.js
, effectively giving you the smallest patch for the UI.Note: the commits in this PR were mostly work in progress to ensure it wasn't lost along the way. The implementation was reworked a bunch of times to where it is now.