@@ -24,7 +24,6 @@ import type {
2424 FlightData ,
2525} from '../../server/app-render/types'
2626import type { ErrorComponent } from './error-boundary'
27- import { reducer } from './router-reducer/router-reducer'
2827import {
2928 ACTION_FAST_REFRESH ,
3029 ACTION_NAVIGATE ,
@@ -36,7 +35,6 @@ import {
3635 PrefetchKind ,
3736} from './router-reducer/router-reducer-types'
3837import type {
39- Mutable ,
4038 ReducerActions ,
4139 RouterChangeByServerResponse ,
4240 RouterNavigate ,
@@ -47,7 +45,10 @@ import {
4745 SearchParamsContext ,
4846 PathnameContext ,
4947} from '../../shared/lib/hooks-client-context.shared-runtime'
50- import { useReducerWithReduxDevtools } from './use-reducer-with-devtools'
48+ import {
49+ useReducerWithReduxDevtools ,
50+ useUnwrapState ,
51+ } from './use-reducer-with-devtools'
5152import { ErrorBoundary } from './error-boundary'
5253import { createInitialRouterState } from './router-reducer/create-initial-router-state'
5354import type { InitialRouterStateParameters } from './router-reducer/create-initial-router-state'
@@ -73,9 +74,9 @@ export function getServerActionDispatcher() {
7374 return globalServerActionDispatcher
7475}
7576
76- let globalMutable : Mutable [ 'globalMutable' ] = {
77- refresh : ( ) => { } , // noop until the router is initialized
78- }
77+ const globalMutable : {
78+ pendingMpaPath ?: string
79+ } = { }
7980
8081export function urlToUrlWithoutFlightMarker ( url : string ) : URL {
8182 const urlWithoutFlightParameters = new URL ( url , location . origin )
@@ -131,7 +132,7 @@ function HistoryUpdater({ tree, pushRef, canonicalUrl, sync }: any) {
131132 return null
132133}
133134
134- const createEmptyCacheNode = ( ) => ( {
135+ export const createEmptyCacheNode = ( ) => ( {
135136 status : CacheStates . LAZY_INITIALIZED ,
136137 data : null ,
137138 subTreeData : null ,
@@ -145,7 +146,7 @@ function useServerActionDispatcher(dispatch: React.Dispatch<ReducerActions>) {
145146 dispatch ( {
146147 ...actionPayload ,
147148 type : ACTION_SERVER_ACTION ,
148- mutable : { globalMutable } ,
149+ mutable : { } ,
149150 cache : createEmptyCacheNode ( ) ,
150151 } )
151152 } )
@@ -174,7 +175,7 @@ function useChangeByServerResponse(
174175 previousTree,
175176 overrideCanonicalUrl,
176177 cache : createEmptyCacheNode ( ) ,
177- mutable : { globalMutable } ,
178+ mutable : { } ,
178179 } )
179180 } )
180181 } ,
@@ -186,7 +187,6 @@ function useNavigate(dispatch: React.Dispatch<ReducerActions>): RouterNavigate {
186187 return useCallback (
187188 ( href , navigateType , forceOptimisticNavigation , shouldScroll ) => {
188189 const url = new URL ( addBasePath ( href ) , location . href )
189- globalMutable . pendingNavigatePath = createHrefFromUrl ( url )
190190
191191 return dispatch ( {
192192 type : ACTION_NAVIGATE ,
@@ -197,7 +197,7 @@ function useNavigate(dispatch: React.Dispatch<ReducerActions>): RouterNavigate {
197197 shouldScroll : shouldScroll ?? true ,
198198 navigateType,
199199 cache : createEmptyCacheNode ( ) ,
200- mutable : { globalMutable } ,
200+ mutable : { } ,
201201 } )
202202 } ,
203203 [ dispatch ]
@@ -229,25 +229,15 @@ function Router({
229229 } ) ,
230230 [ buildId , children , initialCanonicalUrl , initialTree , initialHead ]
231231 )
232- const [
233- {
234- tree,
235- cache,
236- prefetchCache,
237- pushRef,
238- focusAndScrollRef,
239- canonicalUrl,
240- nextUrl,
241- } ,
242- dispatch ,
243- sync ,
244- ] = useReducerWithReduxDevtools ( reducer , initialState )
232+ const [ reducerState , dispatch , sync ] =
233+ useReducerWithReduxDevtools ( initialState )
245234
246235 useEffect ( ( ) => {
247236 // Ensure initialParallelRoutes is cleaned up from memory once it's used.
248237 initialParallelRoutes = null !
249238 } , [ ] )
250239
240+ const { canonicalUrl } = useUnwrapState ( reducerState )
251241 // Add memoized pathname/query for useSearchParams and usePathname.
252242 const { searchParams, pathname } = useMemo ( ( ) => {
253243 const url = new URL (
@@ -322,7 +312,7 @@ function Router({
322312 dispatch ( {
323313 type : ACTION_REFRESH ,
324314 cache : createEmptyCacheNode ( ) ,
325- mutable : { globalMutable } ,
315+ mutable : { } ,
326316 origin : window . location . origin ,
327317 } )
328318 } )
@@ -338,7 +328,7 @@ function Router({
338328 dispatch ( {
339329 type : ACTION_FAST_REFRESH ,
340330 cache : createEmptyCacheNode ( ) ,
341- mutable : { globalMutable } ,
331+ mutable : { } ,
342332 origin : window . location . origin ,
343333 } )
344334 } )
@@ -356,11 +346,10 @@ function Router({
356346 }
357347 } , [ appRouter ] )
358348
359- useEffect ( ( ) => {
360- globalMutable . refresh = appRouter . refresh
361- } , [ appRouter . refresh ] )
362-
363349 if ( process . env . NODE_ENV !== 'production' ) {
350+ // eslint-disable-next-line react-hooks/rules-of-hooks
351+ const { cache, prefetchCache, tree } = useUnwrapState ( reducerState )
352+
364353 // This hook is in a conditional but that is ok because `process.env.NODE_ENV` never changes
365354 // eslint-disable-next-line react-hooks/rules-of-hooks
366355 useEffect ( ( ) => {
@@ -408,6 +397,7 @@ function Router({
408397 // probably safe because we know this is a singleton component and it's never
409398 // in <Offscreen>. At least I hope so. (It will run twice in dev strict mode,
410399 // but that's... fine?)
400+ const { pushRef } = useUnwrapState ( reducerState )
411401 if ( pushRef . mpaNavigation ) {
412402 // if there's a re-render, we don't want to trigger another redirect if one is already in flight to the same URL
413403 if ( globalMutable . pendingMpaPath !== canonicalUrl ) {
@@ -466,6 +456,9 @@ function Router({
466456 }
467457 } , [ onPopState ] )
468458
459+ const { cache, tree, nextUrl, focusAndScrollRef } =
460+ useUnwrapState ( reducerState )
461+
469462 const head = useMemo ( ( ) => {
470463 return findHeadInCache ( cache , tree [ 1 ] )
471464 } , [ cache , tree ] )
@@ -513,7 +506,7 @@ function Router({
513506 < LayoutRouterContext . Provider
514507 value = { {
515508 childNodes : cache . parallelRoutes ,
516- tree : tree ,
509+ tree,
517510 // Root node always has `url`
518511 // Provided in AppTreeContext to ensure it can be overwritten in layout-router
519512 url : canonicalUrl ,
0 commit comments