@@ -938,23 +938,64 @@ function rerenderReducer<S, I, A>(
938938function mountSyncExternalStore < T > (
939939 subscribe : ( ( ) => void ) => ( ) => void ,
940940 getSnapshot : ( ) => T ,
941+ getServerSnapshot ?: ( ) => T ,
941942) : T {
942943 const fiber = currentlyRenderingFiber ;
943944 const hook = mountWorkInProgressHook ( ) ;
944- // Read the current snapshot from the store on every render. This breaks the
945- // normal rules of React, and only works because store updates are
946- // always synchronous.
947- const nextSnapshot = getSnapshot ( ) ;
948- if ( __DEV__ ) {
949- if ( ! didWarnUncachedGetSnapshot ) {
950- if ( nextSnapshot !== getSnapshot ( ) ) {
951- console . error (
952- 'The result of getSnapshot should be cached to avoid an infinite loop' ,
953- ) ;
954- didWarnUncachedGetSnapshot = true ;
945+
946+ let nextSnapshot ;
947+ const isHydrating = getIsHydrating ( ) ;
948+ if ( isHydrating ) {
949+ if ( getServerSnapshot === undefined ) {
950+ invariant (
951+ false ,
952+ 'Missing getServerSnapshot, which is required for ' +
953+ 'server-rendered content. Will revert to client rendering.' ,
954+ ) ;
955+ }
956+ nextSnapshot = getServerSnapshot ( ) ;
957+ if ( __DEV__ ) {
958+ if ( ! didWarnUncachedGetSnapshot ) {
959+ if ( nextSnapshot !== getServerSnapshot ( ) ) {
960+ console . error (
961+ 'The result of getServerSnapshot should be cached to avoid an infinite loop' ,
962+ ) ;
963+ didWarnUncachedGetSnapshot = true ;
964+ }
955965 }
956966 }
967+ } else {
968+ nextSnapshot = getSnapshot ( ) ;
969+ if ( __DEV__ ) {
970+ if ( ! didWarnUncachedGetSnapshot ) {
971+ if ( nextSnapshot !== getSnapshot ( ) ) {
972+ console . error (
973+ 'The result of getSnapshot should be cached to avoid an infinite loop' ,
974+ ) ;
975+ didWarnUncachedGetSnapshot = true ;
976+ }
977+ }
978+ }
979+ // Unless we're rendering a blocking lane, schedule a consistency check.
980+ // Right before committing, we will walk the tree and check if any of the
981+ // stores were mutated.
982+ //
983+ // We won't do this if we're hydrating server-rendered content, because if
984+ // the content is stale, it's already visible anyway. Instead we'll patch
985+ // it up in a passive effect.
986+ const root : FiberRoot | null = getWorkInProgressRoot ( ) ;
987+ invariant (
988+ root !== null ,
989+ 'Expected a work-in-progress root. This is a bug in React. Please file an issue.' ,
990+ ) ;
991+ if ( ! includesBlockingLane ( root , renderLanes ) ) {
992+ pushStoreConsistencyCheck ( fiber , getSnapshot , nextSnapshot ) ;
993+ }
957994 }
995+
996+ // Read the current snapshot from the store on every render. This breaks the
997+ // normal rules of React, and only works because store updates are
998+ // always synchronous.
958999 hook . memoizedState = nextSnapshot ;
9591000 const inst : StoreInstance < T > = {
9601001 value : nextSnapshot ,
@@ -980,24 +1021,13 @@ function mountSyncExternalStore<T>(
9801021 null ,
9811022 ) ;
9821023
983- // Unless we're rendering a blocking lane, schedule a consistency check. Right
984- // before committing, we will walk the tree and check if any of the stores
985- // were mutated.
986- const root : FiberRoot | null = getWorkInProgressRoot ( ) ;
987- invariant (
988- root !== null ,
989- 'Expected a work-in-progress root. This is a bug in React. Please file an issue.' ,
990- ) ;
991- if ( ! includesBlockingLane ( root , renderLanes ) ) {
992- pushStoreConsistencyCheck ( fiber , getSnapshot , nextSnapshot ) ;
993- }
994-
9951024 return nextSnapshot ;
9961025}
9971026
9981027function updateSyncExternalStore < T > (
9991028 subscribe : ( ( ) => void ) => ( ) => void ,
10001029 getSnapshot : ( ) = > T ,
1030+ getServerSnapshot ? : ( ) => T ,
10011031) : T {
10021032 const fiber = currentlyRenderingFiber ;
10031033 const hook = updateWorkInProgressHook ( ) ;
@@ -2235,10 +2265,11 @@ if (__DEV__) {
22352265 useSyncExternalStore< T > (
22362266 subscribe: (() => void ) => ( ) => void ,
22372267 getSnapshot : ( ) => T ,
2268+ getServerSnapshot ?: ( ) => T ,
22382269 ) : T {
22392270 currentHookNameInDev = 'useSyncExternalStore' ;
22402271 mountHookTypesDev ( ) ;
2241- return mountSyncExternalStore ( subscribe , getSnapshot ) ;
2272+ return mountSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
22422273 } ,
22432274 useOpaqueIdentifier(): OpaqueIDType | void {
22442275 currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2366,10 +2397,11 @@ if (__DEV__) {
23662397 useSyncExternalStore< T > (
23672398 subscribe: (() => void ) => ( ) => void ,
23682399 getSnapshot : ( ) => T ,
2400+ getServerSnapshot ?: ( ) => T ,
23692401 ) : T {
23702402 currentHookNameInDev = 'useSyncExternalStore' ;
23712403 updateHookTypesDev ( ) ;
2372- return mountSyncExternalStore ( subscribe , getSnapshot ) ;
2404+ return mountSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
23732405 } ,
23742406 useOpaqueIdentifier(): OpaqueIDType | void {
23752407 currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2497,10 +2529,11 @@ if (__DEV__) {
24972529 useSyncExternalStore< T > (
24982530 subscribe: (() => void ) => ( ) => void ,
24992531 getSnapshot : ( ) => T ,
2532+ getServerSnapshot ?: ( ) => T ,
25002533 ) : T {
25012534 currentHookNameInDev = 'useSyncExternalStore' ;
25022535 updateHookTypesDev ( ) ;
2503- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
2536+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
25042537 } ,
25052538 useOpaqueIdentifier(): OpaqueIDType | void {
25062539 currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2629,10 +2662,11 @@ if (__DEV__) {
26292662 useSyncExternalStore< T > (
26302663 subscribe: (() => void ) => ( ) => void ,
26312664 getSnapshot : ( ) => T ,
2665+ getServerSnapshot ?: ( ) => T ,
26322666 ) : T {
26332667 currentHookNameInDev = 'useSyncExternalStore' ;
26342668 updateHookTypesDev ( ) ;
2635- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
2669+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
26362670 } ,
26372671 useOpaqueIdentifier(): OpaqueIDType | void {
26382672 currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2774,11 +2808,12 @@ if (__DEV__) {
27742808 useSyncExternalStore< T > (
27752809 subscribe: (() => void ) => ( ) => void ,
27762810 getSnapshot : ( ) => T ,
2811+ getServerSnapshot ?: ( ) => T ,
27772812 ) : T {
27782813 currentHookNameInDev = 'useSyncExternalStore' ;
27792814 warnInvalidHookAccess ( ) ;
27802815 mountHookTypesDev ( ) ;
2781- return mountSyncExternalStore ( subscribe , getSnapshot ) ;
2816+ return mountSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
27822817 } ,
27832818 useOpaqueIdentifier(): OpaqueIDType | void {
27842819 currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2921,11 +2956,12 @@ if (__DEV__) {
29212956 useSyncExternalStore< T > (
29222957 subscribe: (() => void ) => ( ) => void ,
29232958 getSnapshot : ( ) => T ,
2959+ getServerSnapshot ?: ( ) => T ,
29242960 ) : T {
29252961 currentHookNameInDev = 'useSyncExternalStore' ;
29262962 warnInvalidHookAccess ( ) ;
29272963 updateHookTypesDev ( ) ;
2928- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
2964+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
29292965 } ,
29302966 useOpaqueIdentifier(): OpaqueIDType | void {
29312967 currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -3069,11 +3105,12 @@ if (__DEV__) {
30693105 useSyncExternalStore< T > (
30703106 subscribe: (() => void ) => ( ) => void ,
30713107 getSnapshot : ( ) => T ,
3108+ getServerSnapshot ?: ( ) => T ,
30723109 ) : T {
30733110 currentHookNameInDev = 'useSyncExternalStore' ;
30743111 warnInvalidHookAccess ( ) ;
30753112 updateHookTypesDev ( ) ;
3076- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
3113+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
30773114 } ,
30783115 useOpaqueIdentifier(): OpaqueIDType | void {
30793116 currentHookNameInDev = 'useOpaqueIdentifier' ;
0 commit comments