938
function mountSyncExternalStore<T>(
939
subscribe: (() => void) => () => void,
940
getSnapshot: () => T,
941
+ getServerSnapshot?: () => T,
942
): T {
943
const fiber = currentlyRenderingFiber;
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
+ }
965
}
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
+ }
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.
999
hook.memoizedState = nextSnapshot;
1000
const inst: StoreInstance<T> = {
1001
value: nextSnapshot,
1021
null,
1022
);
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
-
1024
return nextSnapshot;
1025
}
1026
1027
function updateSyncExternalStore<T>(
1028
subscribe: (() => void) => () => void,
1029
getSnapshot: () => T,
1030
+ getServerSnapshot?: () => T,
1031
): T {
1032
const fiber = currentlyRenderingFiber;
1033
const hook = updateWorkInProgressHook();
2265
useSyncExternalStore<T>(
2266
subscribe: (() => void) => () => void,
2267
getSnapshot: () => T,
2268
+ getServerSnapshot?: () => T,
2269
): T {
2270
currentHookNameInDev = 'useSyncExternalStore';
2271
mountHookTypesDev();
2241
- return mountSyncExternalStore(subscribe, getSnapshot);
2272
+ return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2273
},
2274
useOpaqueIdentifier(): OpaqueIDType | void {
2275
currentHookNameInDev = 'useOpaqueIdentifier';
2397
useSyncExternalStore<T>(
2398
subscribe: (() => void) => () => void,
2399
getSnapshot: () => T,
2400
+ getServerSnapshot?: () => T,
2401
): T {
2402
currentHookNameInDev = 'useSyncExternalStore';
2403
updateHookTypesDev();
2372
- return mountSyncExternalStore(subscribe, getSnapshot);
2404
+ return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2405
},
2406
useOpaqueIdentifier(): OpaqueIDType | void {
2407
currentHookNameInDev = 'useOpaqueIdentifier';
2529
useSyncExternalStore<T>(
2530
subscribe: (() => void) => () => void,
2531
getSnapshot: () => T,
2532
+ getServerSnapshot?: () => T,
2533
): T {
2534
currentHookNameInDev = 'useSyncExternalStore';
2535
updateHookTypesDev();
2503
- return updateSyncExternalStore(subscribe, getSnapshot);
2536
+ return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2537
},
2538
useOpaqueIdentifier(): OpaqueIDType | void {
2539
currentHookNameInDev = 'useOpaqueIdentifier';
2662
useSyncExternalStore<T>(
2663
subscribe: (() => void) => () => void,
2664
getSnapshot: () => T,
2665
+ getServerSnapshot?: () => T,
2666
): T {
2667
currentHookNameInDev = 'useSyncExternalStore';
2668
updateHookTypesDev();
2635
- return updateSyncExternalStore(subscribe, getSnapshot);
2669
+ return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2670
},
2671
useOpaqueIdentifier(): OpaqueIDType | void {
2672
currentHookNameInDev = 'useOpaqueIdentifier';
2808
useSyncExternalStore<T>(
2809
subscribe: (() => void) => () => void,
2810
getSnapshot: () => T,
2811
+ getServerSnapshot?: () => T,
2812
): T {
2813
currentHookNameInDev = 'useSyncExternalStore';
2814
warnInvalidHookAccess();
2815
mountHookTypesDev();
2781
- return mountSyncExternalStore(subscribe, getSnapshot);
2816
+ return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2817
},
2818
useOpaqueIdentifier(): OpaqueIDType | void {
2819
currentHookNameInDev = 'useOpaqueIdentifier';
2956
useSyncExternalStore<T>(
2957
subscribe: (() => void) => () => void,
2958
getSnapshot: () => T,
2959
+ getServerSnapshot?: () => T,
2960
): T {
2961
currentHookNameInDev = 'useSyncExternalStore';
2962
warnInvalidHookAccess();
2963
updateHookTypesDev();
2928
- return updateSyncExternalStore(subscribe, getSnapshot);
2964
+ return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2965
},
2966
useOpaqueIdentifier(): OpaqueIDType | void {
2967
currentHookNameInDev = 'useOpaqueIdentifier';
3105
useSyncExternalStore<T>(
3106
subscribe: (() => void) => () => void,
3107
getSnapshot: () => T,
3108
+ getServerSnapshot?: () => T,
3109
): T {
3110
currentHookNameInDev = 'useSyncExternalStore';
3111
warnInvalidHookAccess();
3112
updateHookTypesDev();
3076
- return updateSyncExternalStore(subscribe, getSnapshot);
3113
+ return updateSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
3114
},
3115
useOpaqueIdentifier(): OpaqueIDType | void {
3116
currentHookNameInDev = 'useOpaqueIdentifier';