mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
### Depends on - #60577 --- A popstate navigation reads data from the local cache. It does not issue new network requests (unless the cache entries have been evicted). So, when navigating with back/forward, we should not switch back to the PPR loading state. We should render the full, cached dynamic data immediately. To implement this, on a popstate navigation, we update the cache to drop the prefetch data for any segment whose dynamic data was already received. We clone the entire cache node tree and set the `prefetchRsc` field to `null` to prevent it from being rendered. (We can't mutate the node in place because Cache Node is a concurrent data structure.) Technically, what we're actually checking is whether the dynamic network response was received. But since it's a streaming response, this does not mean that all the dynamic data has fully streamed in. It just means that _some_ of the dynamic data was received. But as a heuristic, we assume that the rest dynamic data will stream in quickly, so it's still better to skip the prefetch state. Closes NEXT-2084
46 lines
1.2 KiB
TypeScript
46 lines
1.2 KiB
TypeScript
'use client'
|
|
|
|
import { Component, createContext, use, useState } from 'react'
|
|
|
|
const ShouldFallbackThrowContext = createContext(false)
|
|
|
|
export function ShouldFallbackThrowContainer({ children }) {
|
|
const [shouldFallbackThrow, setShouldFallbackThrow] = useState(false)
|
|
return (
|
|
<>
|
|
<label>
|
|
Throw if fallback appears
|
|
<input
|
|
id="should-fallback-throw"
|
|
type="checkbox"
|
|
checked={shouldFallbackThrow}
|
|
onChange={(e) => setShouldFallbackThrow(e.target.checked)}
|
|
/>
|
|
</label>
|
|
<ShouldFallbackThrowContext.Provider value={shouldFallbackThrow}>
|
|
<ErrorBoundary>{children}</ErrorBoundary>
|
|
</ShouldFallbackThrowContext.Provider>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export function Fallback({ children }) {
|
|
if (use(ShouldFallbackThrowContext)) {
|
|
throw new Error('Unexpected fallback')
|
|
}
|
|
return children
|
|
}
|
|
|
|
class ErrorBoundary extends Component<{ children: React.ReactNode }> {
|
|
state = { error: null }
|
|
static getDerivedStateFromError(error) {
|
|
return { error }
|
|
}
|
|
render() {
|
|
if (this.state.error) {
|
|
return <div id="error">{this.state.error.message}</div>
|
|
}
|
|
return this.props.children
|
|
}
|
|
}
|