Skip to content

Commit

Permalink
Prevent storing page props cache when in SSG + preview mode (#30757)
Browse files Browse the repository at this point in the history
In Next 12, `router.replace()` treats the page props cache as authoritative when fetching SSG props in preview mode. This makes sense outside preview mode (static props won't change), but within preview mode this prevents reloading the preview data dynamically without force-refreshing the page.

This PR fixes the problem by instructing Next to bypass the props cache if it's an SSG route AND preview mode is on.

Repro: https://github.com/kamsar/next-replace-previewmode-staticprops/blob/main/pages/index.js



## Bug

- [x] Related issues linked using `fixes #number`: Fixes #30756
- [ ] Integration tests added: Did not find existing tests for the router, but I'd be happy to write one if someone could point me in the right direction.
  • Loading branch information
kamsar committed Nov 2, 2021
1 parent 597594d commit b95bc4b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/next/shared/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ export default class Router implements BaseRouter {
this.isSsr,
false,
__N_SSG ? this.sdc : this.sdr,
!!__N_SSG
!!__N_SSG && !this.isPreview
)
: this.getInitialProps(
Component,
Expand Down
20 changes: 18 additions & 2 deletions test/integration/prerender-preview/pages/index.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
import { useState } from 'react'
import { useRouter } from 'next/router'

export function getStaticProps({ preview, previewData }) {
return {
props: {
hasProps: true,
random: Math.random(),
preview: !!preview,
previewData: previewData || null,
},
}
}

export default function ({ hasProps, preview, previewData }) {
export default function ({ hasProps, preview, previewData, random }) {
const router = useRouter()
const [reloaded, setReloaded] = useState(false)

return (
<>
<pre id="props-pre">
{hasProps
? JSON.stringify(preview) + ' and ' + JSON.stringify(previewData)
: 'Has No Props'}
</pre>
<p id="router">{JSON.stringify(useRouter())}</p>
<pre id="ssg-random">{random}</pre>
{reloaded ? <pre id="ssg-reloaded">Reloaded</pre> : null}
<button
id="reload-props"
onClick={async () => {
await router.replace(router.asPath)
setReloaded(true)
}}
>
Reload static props
</button>
<p id="router">{JSON.stringify(router)}</p>
</>
)
}
18 changes: 18 additions & 0 deletions test/integration/prerender-preview/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,24 @@ describe('Prerender Preview Mode', () => {
)
})

it('should fetch live static props with preview active', async () => {
await browser.get(`http://localhost:${appPort}/`)

await browser.waitForElementByCss('#ssg-random')
const initialRandom = await browser.elementById('ssg-random').text()

// reload static props with router.replace
await browser.elementById('reload-props').click()

// wait for route change to complete and set updated state
await browser.waitForElementByCss('#ssg-reloaded')

// assert that the random number from static props has changed (thus, was re-evaluated)
expect(await browser.elementById('ssg-random').text()).not.toBe(
initialRandom
)
})

afterAll(async () => {
await browser.close()
await killApp(app)
Expand Down

0 comments on commit b95bc4b

Please sign in to comment.