@@ -938,23 +938,64 @@ function rerenderReducer<S, I, A>(
938
938
function mountSyncExternalStore < T > (
939
939
subscribe : ( ( ) => void ) => ( ) => void ,
940
940
getSnapshot : ( ) => T ,
941
+ getServerSnapshot ?: ( ) => T ,
941
942
) : T {
942
943
const fiber = currentlyRenderingFiber ;
943
944
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
+ }
955
965
}
956
966
}
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
+ }
957
994
}
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.
958
999
hook . memoizedState = nextSnapshot ;
959
1000
const inst : StoreInstance < T > = {
960
1001
value : nextSnapshot ,
@@ -980,24 +1021,13 @@ function mountSyncExternalStore<T>(
980
1021
null ,
981
1022
) ;
982
1023
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
-
995
1024
return nextSnapshot ;
996
1025
}
997
1026
998
1027
function updateSyncExternalStore < T > (
999
1028
subscribe : ( ( ) => void ) => ( ) => void ,
1000
1029
getSnapshot : ( ) = > T ,
1030
+ getServerSnapshot ? : ( ) => T ,
1001
1031
) : T {
1002
1032
const fiber = currentlyRenderingFiber ;
1003
1033
const hook = updateWorkInProgressHook ( ) ;
@@ -2235,10 +2265,11 @@ if (__DEV__) {
2235
2265
useSyncExternalStore< T > (
2236
2266
subscribe: (() => void ) => ( ) => void ,
2237
2267
getSnapshot : ( ) => T ,
2268
+ getServerSnapshot ?: ( ) => T ,
2238
2269
) : T {
2239
2270
currentHookNameInDev = 'useSyncExternalStore' ;
2240
2271
mountHookTypesDev ( ) ;
2241
- return mountSyncExternalStore ( subscribe , getSnapshot ) ;
2272
+ return mountSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
2242
2273
} ,
2243
2274
useOpaqueIdentifier(): OpaqueIDType | void {
2244
2275
currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2366,10 +2397,11 @@ if (__DEV__) {
2366
2397
useSyncExternalStore< T > (
2367
2398
subscribe: (() => void ) => ( ) => void ,
2368
2399
getSnapshot : ( ) => T ,
2400
+ getServerSnapshot ?: ( ) => T ,
2369
2401
) : T {
2370
2402
currentHookNameInDev = 'useSyncExternalStore' ;
2371
2403
updateHookTypesDev ( ) ;
2372
- return mountSyncExternalStore ( subscribe , getSnapshot ) ;
2404
+ return mountSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
2373
2405
} ,
2374
2406
useOpaqueIdentifier(): OpaqueIDType | void {
2375
2407
currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2497,10 +2529,11 @@ if (__DEV__) {
2497
2529
useSyncExternalStore< T > (
2498
2530
subscribe: (() => void ) => ( ) => void ,
2499
2531
getSnapshot : ( ) => T ,
2532
+ getServerSnapshot ?: ( ) => T ,
2500
2533
) : T {
2501
2534
currentHookNameInDev = 'useSyncExternalStore' ;
2502
2535
updateHookTypesDev ( ) ;
2503
- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
2536
+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
2504
2537
} ,
2505
2538
useOpaqueIdentifier(): OpaqueIDType | void {
2506
2539
currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2629,10 +2662,11 @@ if (__DEV__) {
2629
2662
useSyncExternalStore< T > (
2630
2663
subscribe: (() => void ) => ( ) => void ,
2631
2664
getSnapshot : ( ) => T ,
2665
+ getServerSnapshot ?: ( ) => T ,
2632
2666
) : T {
2633
2667
currentHookNameInDev = 'useSyncExternalStore' ;
2634
2668
updateHookTypesDev ( ) ;
2635
- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
2669
+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
2636
2670
} ,
2637
2671
useOpaqueIdentifier(): OpaqueIDType | void {
2638
2672
currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2774,11 +2808,12 @@ if (__DEV__) {
2774
2808
useSyncExternalStore< T > (
2775
2809
subscribe: (() => void ) => ( ) => void ,
2776
2810
getSnapshot : ( ) => T ,
2811
+ getServerSnapshot ?: ( ) => T ,
2777
2812
) : T {
2778
2813
currentHookNameInDev = 'useSyncExternalStore' ;
2779
2814
warnInvalidHookAccess ( ) ;
2780
2815
mountHookTypesDev ( ) ;
2781
- return mountSyncExternalStore ( subscribe , getSnapshot ) ;
2816
+ return mountSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
2782
2817
} ,
2783
2818
useOpaqueIdentifier(): OpaqueIDType | void {
2784
2819
currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -2921,11 +2956,12 @@ if (__DEV__) {
2921
2956
useSyncExternalStore< T > (
2922
2957
subscribe: (() => void ) => ( ) => void ,
2923
2958
getSnapshot : ( ) => T ,
2959
+ getServerSnapshot ?: ( ) => T ,
2924
2960
) : T {
2925
2961
currentHookNameInDev = 'useSyncExternalStore' ;
2926
2962
warnInvalidHookAccess ( ) ;
2927
2963
updateHookTypesDev ( ) ;
2928
- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
2964
+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
2929
2965
} ,
2930
2966
useOpaqueIdentifier(): OpaqueIDType | void {
2931
2967
currentHookNameInDev = 'useOpaqueIdentifier' ;
@@ -3069,11 +3105,12 @@ if (__DEV__) {
3069
3105
useSyncExternalStore< T > (
3070
3106
subscribe: (() => void ) => ( ) => void ,
3071
3107
getSnapshot : ( ) => T ,
3108
+ getServerSnapshot ?: ( ) => T ,
3072
3109
) : T {
3073
3110
currentHookNameInDev = 'useSyncExternalStore' ;
3074
3111
warnInvalidHookAccess ( ) ;
3075
3112
updateHookTypesDev ( ) ;
3076
- return updateSyncExternalStore ( subscribe , getSnapshot ) ;
3113
+ return updateSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot ) ;
3077
3114
} ,
3078
3115
useOpaqueIdentifier(): OpaqueIDType | void {
3079
3116
currentHookNameInDev = 'useOpaqueIdentifier' ;
0 commit comments