rsnext/test/e2e/app-dir/parallel-routes-revalidation/app/page.tsx

27 lines
727 B
TypeScript
Raw Normal View History

Fix parallel routes with server actions / revalidating router cache (#59585) ### What? There are a bunch of different bugs caused by the same underlying issue, but the common thread is that performing any sort of router cache update (either through `router.refresh()`, `revalidatePath()`, or `redirect()`) inside of a parallel route would break the router preventing subsequent actions, and not resolve any pending state such as from `useFormState`. ### Why? `applyPatch` is responsible for taking an update response from the server and merging it into the client router cache. However, there's specific bailout logic to skip over applying the patch to a `__DEFAULT__` segment (which corresponds with a `default.tsx` page). When the router detects a cache node that is expected to be rendered on the page but contains no data, the router will trigger a lazy fetch to retrieve the data that's expected to be there ([ref](https://github.com/vercel/next.js/blob/5adacb69126e0fd7dff7ebd45278c0dfd42f6116/packages/next/src/client/components/layout-router.tsx#L359-L370)) and then update the router cache once the data resolves ([ref](https://github.com/vercel/next.js/blob/5adacb69126e0fd7dff7ebd45278c0dfd42f6116/packages/next/src/client/components/layout-router.tsx#L399-L404)). This is causing the router to get stuck in a loop: it'll fetch the data for the cache node, send the data to the router reducer to merge it into the existing cache nodes, skip merging that data in for `__DEFAULT__` segments, and repeat. ### How? We currently assign `__DEFAULT__` to have `notFound()` behavior when there isn't a `default.tsx` component for a particular segment. This makes it so that when loading a page that renders a slot without slot content / a `default`, it 404s. But when performing a client-side navigation, the intended behavior is different: we keep whatever was in the `default` slots place, until the user refreshes the page, which would then 404. However, this logic is incorrect when triggering any of the above mentioned cache node revalidation strategies: if we always skip applying to the `__DEFAULT__` segment, slots will never properly handle reducer actions that rely on making changes to their cache nodes. This splits these different `applyPatch` functions: one that will apply to the full tree, and another that'll apply to everything except the default segments with the existing bailout condition. Fixes #54173 Fixes #58772 Fixes #54723 Fixes #57665 Closes NEXT-1706 Closes NEXT-1815 Closes NEXT-1812
2023-12-15 16:51:14 +01:00
import Link from 'next/link'
import { getData } from './actions'
export default async function Home() {
const data = await getData()
const randomNumber = await fetch(
'https://next-data-api-endpoint.vercel.app/api/random'
).then((res) => res.text())
return (
<div>
<Link href="/revalidate-modal">Open Revalidate Modal</Link>
<Link href="/refresh-modal">Open Refresh Modal</Link>
<Link href="/redirect-modal">Open Redirect Modal</Link>
<div id="random-number">{randomNumber}</div>
<div>
<h1>Current Data</h1>
<ul id="entries">
{data.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
</div>
)
}