@@ -371,144 +371,6 @@ export interface RouterProviderProps {
371371 unstable_transitions ?: boolean ;
372372}
373373
374- function shallowDiff ( a : any , b : any ) {
375- if ( a === b ) {
376- return false ;
377- }
378- let aKeys = Object . keys ( a ) ;
379- let bKeys = Object . keys ( b ) ;
380- if ( aKeys . length !== bKeys . length ) {
381- return true ;
382- }
383- for ( let key of aKeys ) {
384- if ( a [ key ] !== b [ key ] ) {
385- return true ;
386- }
387- }
388- return false ;
389- }
390-
391- export function UNSTABLE_TransitionEnabledRouterProvider ( {
392- router,
393- flushSync : reactDomFlushSyncImpl ,
394- unstable_onError,
395- } : Omit < RouterProviderProps , "unstable_transitions" > ) : React . ReactElement {
396- let fetcherData = React . useRef < Map < string , any > > ( new Map ( ) ) ;
397- let [ revalidating , startRevalidation ] = React . useTransition ( ) ;
398- let [ state , setState ] = React . useState ( router . state ) ;
399-
400- ( router as any ) . __setPendingRerender = ( promise : Promise < ( ) => void > ) =>
401- startRevalidation (
402- // @ts -expect-error - need react 19 types for this to be async
403- async ( ) => {
404- const rerender = await promise ;
405- startRevalidation ( ( ) => {
406- rerender ( ) ;
407- } ) ;
408- } ,
409- ) ;
410-
411- let navigator = React . useMemo ( ( ) : Navigator => {
412- return {
413- createHref : router . createHref ,
414- encodeLocation : router . encodeLocation ,
415- go : ( n ) => router . navigate ( n ) ,
416- push : ( to , state , opts ) =>
417- router . navigate ( to , {
418- state,
419- preventScrollReset : opts ?. preventScrollReset ,
420- } ) ,
421- replace : ( to , state , opts ) =>
422- router . navigate ( to , {
423- replace : true ,
424- state,
425- preventScrollReset : opts ?. preventScrollReset ,
426- } ) ,
427- } ;
428- } , [ router ] ) ;
429-
430- let basename = router . basename || "/" ;
431-
432- let dataRouterContext = React . useMemo (
433- ( ) => ( {
434- router,
435- navigator,
436- static : false ,
437- basename,
438- unstable_onError,
439- } ) ,
440- [ router , navigator , basename , unstable_onError ] ,
441- ) ;
442-
443- React . useLayoutEffect ( ( ) => {
444- return router . subscribe (
445- ( newState , { deletedFetchers, flushSync, viewTransitionOpts } ) => {
446- newState . fetchers . forEach ( ( fetcher , key ) => {
447- if ( fetcher . data !== undefined ) {
448- fetcherData . current . set ( key , fetcher . data ) ;
449- }
450- } ) ;
451- deletedFetchers . forEach ( ( key ) => fetcherData . current . delete ( key ) ) ;
452-
453- const diff = shallowDiff ( state , newState ) ;
454-
455- if ( ! diff ) return ;
456-
457- if ( flushSync ) {
458- if ( reactDomFlushSyncImpl ) {
459- reactDomFlushSyncImpl ( ( ) => setState ( newState ) ) ;
460- } else {
461- setState ( newState ) ;
462- }
463- } else {
464- React . startTransition ( ( ) => {
465- setState ( newState ) ;
466- } ) ;
467- }
468- } ,
469- ) ;
470- } , [ router , reactDomFlushSyncImpl , state ] ) ;
471-
472- // The fragment and {null} here are important! We need them to keep React 18's
473- // useId happy when we are server-rendering since we may have a <script> here
474- // containing the hydrated server-side staticContext (from StaticRouterProvider).
475- // useId relies on the component tree structure to generate deterministic id's
476- // so we need to ensure it remains the same on the client even though
477- // we don't need the <script> tag
478- return (
479- < >
480- < DataRouterContext . Provider value = { dataRouterContext } >
481- < DataRouterStateContext . Provider
482- value = { {
483- ...state ,
484- revalidation : revalidating ? "loading" : state . revalidation ,
485- } }
486- >
487- < FetchersContext . Provider value = { fetcherData . current } >
488- { /* <ViewTransitionContext.Provider value={vtContext}> */ }
489- < Router
490- basename = { basename }
491- location = { state . location }
492- navigationType = { state . historyAction }
493- navigator = { navigator }
494- unstable_transitions = { true }
495- >
496- < MemoizedDataRoutes
497- routes = { router . routes }
498- future = { router . future }
499- state = { state }
500- unstable_onError = { unstable_onError }
501- />
502- </ Router >
503- { /* </ViewTransitionContext.Provider> */ }
504- </ FetchersContext . Provider >
505- </ DataRouterStateContext . Provider >
506- </ DataRouterContext . Provider >
507- { null }
508- </ >
509- ) ;
510- }
511-
512374/**
513375 * Render the UI for the given {@link DataRouter}. This component should
514376 * typically be at the top of an app's element tree.
@@ -548,6 +410,8 @@ export function RouterProvider({
548410 unstable_transitions,
549411} : RouterProviderProps ) : React . ReactElement {
550412 let [ _state , setStateImpl ] = React . useState ( router . state ) ;
413+ let navigationRef = React . useRef ( _state . navigation ) ;
414+ let [ pending , startTransition ] = React . useTransition ( ) ;
551415 // @ts -expect-error - Needs React 19 types
552416 let [ state , setOptimisticState ] = React . useOptimistic ( _state ) ;
553417 let [ pendingState , setPendingState ] = React . useState < RouterState > ( ) ;
@@ -624,9 +488,16 @@ export function RouterProvider({
624488 } else if ( unstable_transitions === false ) {
625489 logErrorsAndSetState ( newState ) ;
626490 } else {
627- React . startTransition ( ( ) => {
491+ startTransition ( ( ) => {
628492 if ( unstable_transitions === true ) {
629- setOptimisticState ( newState ) ;
493+ if ( newState . navigation . state !== "idle" ) {
494+ navigationRef . current = newState . navigation ;
495+ }
496+ setOptimisticState ( ( state : any ) => ( {
497+ ...state ,
498+ navigation : navigationRef . current ,
499+ revalidation : newState . revalidation ,
500+ } ) ) ;
630501 }
631502 logErrorsAndSetState ( newState ) ;
632503 } ) ;
@@ -726,9 +597,16 @@ export function RouterProvider({
726597 if ( unstable_transitions === false ) {
727598 logErrorsAndSetState ( newState ) ;
728599 } else {
729- React . startTransition ( ( ) => {
600+ startTransition ( ( ) => {
730601 if ( unstable_transitions === true ) {
731- setOptimisticState ( newState ) ;
602+ if ( newState . navigation . state !== "idle" ) {
603+ navigationRef . current = newState . navigation ;
604+ }
605+ setOptimisticState ( ( state : any ) => ( {
606+ ...state ,
607+ navigation : newState . navigation ,
608+ revalidation : newState . revalidation ,
609+ } ) ) ;
732610 }
733611 logErrorsAndSetState ( newState ) ;
734612 } ) ;
@@ -783,18 +661,59 @@ export function RouterProvider({
783661 return {
784662 createHref : router . createHref ,
785663 encodeLocation : router . encodeLocation ,
786- go : ( n ) => router . navigate ( n ) ,
787- push : ( to , state , opts ) =>
788- router . navigate ( to , {
664+ go : ( n ) => {
665+ if ( unstable_transitions === true ) {
666+ const resolver = new Deferred < void > ( ) ;
667+ // @ts -expect-error - Needs React 19 types
668+ startTransition ( ( ) => {
669+ return router . navigate ( n ) . then ( resolver . resolve , resolver . reject ) ;
670+ } ) ;
671+ return resolver . promise ;
672+ }
673+ return router . navigate ( n ) ;
674+ } ,
675+ push : ( to , state , opts ) => {
676+ if ( unstable_transitions === true ) {
677+ const resolver = new Deferred < void > ( ) ;
678+ // @ts -expect-error - Needs React 19 types
679+ startTransition ( ( ) => {
680+ return router
681+ . navigate ( to , {
682+ state,
683+ preventScrollReset : opts ?. preventScrollReset ,
684+ } )
685+ . then ( resolver . resolve , resolver . reject ) ;
686+ } ) ;
687+ return resolver . promise ;
688+ }
689+
690+ return router . navigate ( to , {
789691 state,
790692 preventScrollReset : opts ?. preventScrollReset ,
791- } ) ,
792- replace : ( to , state , opts ) =>
793- router . navigate ( to , {
693+ } ) ;
694+ } ,
695+ replace : ( to , state , opts ) => {
696+ if ( unstable_transitions === true ) {
697+ const resolver = new Deferred < void > ( ) ;
698+ // @ts -expect-error - Needs React 19 types
699+ startTransition ( ( ) => {
700+ return router
701+ . navigate ( to , {
702+ replace : true ,
703+ state,
704+ preventScrollReset : opts ?. preventScrollReset ,
705+ } )
706+ . then ( resolver . resolve , resolver . reject ) ;
707+ } ) ;
708+ return resolver . promise ;
709+ }
710+
711+ return router . navigate ( to , {
794712 replace : true ,
795713 state,
796714 preventScrollReset : opts ?. preventScrollReset ,
797- } ) ,
715+ } ) ;
716+ } ,
798717 } ;
799718 } , [ router ] ) ;
800719
@@ -833,7 +752,14 @@ export function RouterProvider({
833752 < MemoizedDataRoutes
834753 routes = { router . routes }
835754 future = { router . future }
836- state = { state }
755+ state = {
756+ pending
757+ ? {
758+ ...state ,
759+ navigation : navigationRef . current ,
760+ }
761+ : state
762+ }
837763 unstable_onError = { unstable_onError }
838764 />
839765 </ Router >
0 commit comments