Skip to content

Commit

Permalink
Add handling for back/forward (popstate) between old and new router (#…
Browse files Browse the repository at this point in the history
…38453)

Handles the case where you navigate between routes in `pages` and `app`.



## 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)
  • Loading branch information
timneutkens authored Jul 8, 2022
1 parent bb0013f commit a4668f2
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 10 deletions.
18 changes: 15 additions & 3 deletions packages/next/client/components/app-router.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,16 @@ export default function AppRouter({
return
}

// Identifier is shortened intentionally.
// __NA is used to identify if the history entry can be handled by the app-router.
// __N is used to identify if the history entry can be handled by the old router.
const historyState = { __NA: true, tree }
if (pushRef.pendingPush) {
pushRef.pendingPush = false
window.history.pushState({ tree }, '', canonicalUrl)

window.history.pushState(historyState, '', canonicalUrl)
} else {
window.history.replaceState({ tree }, '', canonicalUrl)
window.history.replaceState(historyState, '', canonicalUrl)
}
}, [tree, pushRef, canonicalUrl])

Expand All @@ -185,6 +190,13 @@ export default function AppRouter({
return
}

// TODO: this case happens when pushState/replaceState was called outside of Next.js or when the history entry was pushed by the old router.
// It reloads the page in this case but we might have to revisit this as the old router ignores it.
if (!state.__NA) {
window.location.reload()
return
}

// @ts-ignore useTransition exists
// TODO: Ideally the back button should not use startTransition as it should apply the updates synchronously
// Without startTransition works if the cache is there for this path
Expand All @@ -193,7 +205,7 @@ export default function AppRouter({
type: 'restore',
payload: {
url: new URL(window.location.href),
historyState: state,
tree: state.tree,
},
})
})
Expand Down
8 changes: 3 additions & 5 deletions packages/next/client/components/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ type AppRouterState = {
canonicalUrl: string
}

type HistoryState = { tree: FlightRouterState }

export function reducer(
state: AppRouterState,
action:
Expand All @@ -265,7 +263,7 @@ export function reducer(
}
}
}
| { type: 'restore'; payload: { url: URL; historyState: HistoryState } }
| { type: 'restore'; payload: { url: URL; tree: FlightRouterState } }
| {
type: 'server-patch'
payload: {
Expand All @@ -276,14 +274,14 @@ export function reducer(
}
): AppRouterState {
if (action.type === 'restore') {
const { url, historyState } = action.payload
const { url, tree } = action.payload
const href = url.pathname + url.search + url.hash

return {
canonicalUrl: href,
pushRef: state.pushRef,
cache: state.cache,
tree: historyState.tree,
tree: tree,
}
}

Expand Down
11 changes: 9 additions & 2 deletions packages/next/shared/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ interface NextHistoryState {

export type HistoryState =
| null
| { __N: false }
| ({ __N: true; key: string } & NextHistoryState)
| { __NA: true; __N?: false }
| { __N: false; __NA?: false }
| ({ __NA?: false; __N: true; key: string } & NextHistoryState)

function buildCancellationError() {
return Object.assign(new Error('Route Cancelled'), {
Expand Down Expand Up @@ -840,6 +841,12 @@ export default class Router implements BaseRouter {
return
}

// __NA is used to identify if the history entry can be handled by the app-router.
if (state.__NA) {
window.location.reload()
return
}

if (!state.__N) {
return
}
Expand Down

0 comments on commit a4668f2

Please sign in to comment.