1 | import { invariant } from "../../utilities/globals/index.js";
|
2 | import * as React from "rehackt";
|
3 | import { canUseLayoutEffect } from "../../utilities/index.js";
|
4 | var didWarnUncachedGetSnapshot = false;
|
5 | // Prevent webpack from complaining about our feature detection of the
|
6 | // useSyncExternalStore property of the React namespace, which is expected not
|
7 | // to exist when using React 17 and earlier, and that's fine.
|
8 | var uSESKey = "useSyncExternalStore";
|
9 | var realHook = React[uSESKey];
|
10 | // Adapted from https://www.npmjs.com/package/use-sync-external-store, with
|
11 | // Apollo Client deviations called out by "// DEVIATION ..." comments.
|
12 | // When/if React.useSyncExternalStore is defined, delegate fully to it.
|
13 | export var useSyncExternalStore = realHook ||
|
14 | (function (subscribe, getSnapshot, getServerSnapshot) {
|
15 | // Read the current snapshot from the store on every render. Again, this
|
16 | // breaks the rules of React, and only works here because of specific
|
17 | // implementation details, most importantly that updates are
|
18 | // always synchronous.
|
19 | var value = getSnapshot();
|
20 | if (
|
21 | // DEVIATION: Using __DEV__
|
22 | globalThis.__DEV__ !== false &&
|
23 | !didWarnUncachedGetSnapshot &&
|
24 | // DEVIATION: Not using Object.is because we know our snapshots will never
|
25 | // be exotic primitive values like NaN, which is !== itself.
|
26 | value !== getSnapshot()) {
|
27 | didWarnUncachedGetSnapshot = true;
|
28 | // DEVIATION: Using invariant.error instead of console.error directly.
|
29 | globalThis.__DEV__ !== false && invariant.error(60);
|
30 | }
|
31 | // Because updates are synchronous, we don't queue them. Instead we force a
|
32 | // re-render whenever the subscribed state changes by updating an some
|
33 | // arbitrary useState hook. Then, during render, we call getSnapshot to read
|
34 | // the current value.
|
35 | //
|
36 | // Because we don't actually use the state returned by the useState hook, we
|
37 | // can save a bit of memory by storing other stuff in that slot.
|
38 | //
|
39 | // To implement the early bailout, we need to track some things on a mutable
|
40 | // object. Usually, we would put that in a useRef hook, but we can stash it in
|
41 | // our useState hook instead.
|
42 | //
|
43 | // To force a re-render, we call forceUpdate({inst}). That works because the
|
44 | // new object always fails an equality check.
|
45 | var _a = React.useState({
|
46 | inst: { value: value, getSnapshot: getSnapshot },
|
47 | }), inst = _a[0].inst, forceUpdate = _a[1];
|
48 | // Track the latest getSnapshot function with a ref. This needs to be updated
|
49 | // in the layout phase so we can access it during the tearing check that
|
50 | // happens on subscribe.
|
51 | if (canUseLayoutEffect) {
|
52 | // DEVIATION: We avoid calling useLayoutEffect when !canUseLayoutEffect,
|
53 | // which may seem like a conditional hook, but this code ends up behaving
|
54 | // unconditionally (one way or the other) because canUseLayoutEffect is
|
55 | // constant.
|
56 | React.useLayoutEffect(function () {
|
57 | Object.assign(inst, { value: value, getSnapshot: getSnapshot });
|
58 | // Whenever getSnapshot or subscribe changes, we need to check in the
|
59 | // commit phase if there was an interleaved mutation. In concurrent mode
|
60 | // this can happen all the time, but even in synchronous mode, an earlier
|
61 | // effect may have mutated the store.
|
62 | if (checkIfSnapshotChanged(inst)) {
|
63 | // Force a re-render.
|
64 | forceUpdate({ inst: inst });
|
65 | }
|
66 | // React Hook React.useLayoutEffect has a missing dependency: 'inst'. Either include it or remove the dependency array.
|
67 | // eslint-disable-next-line react-hooks/exhaustive-deps
|
68 | }, [subscribe, value, getSnapshot]);
|
69 | }
|
70 | else {
|
71 | Object.assign(inst, { value: value, getSnapshot: getSnapshot });
|
72 | }
|
73 | React.useEffect(function () {
|
74 | // Check for changes right before subscribing. Subsequent changes will be
|
75 | // detected in the subscription handler.
|
76 | if (checkIfSnapshotChanged(inst)) {
|
77 | // Force a re-render.
|
78 | forceUpdate({ inst: inst });
|
79 | }
|
80 | // Subscribe to the store and return a clean-up function.
|
81 | return subscribe(function handleStoreChange() {
|
82 | // TODO: Because there is no cross-renderer API for batching updates, it's
|
83 | // up to the consumer of this library to wrap their subscription event
|
84 | // with unstable_batchedUpdates. Should we try to detect when this isn't
|
85 | // the case and print a warning in development?
|
86 | // The store changed. Check if the snapshot changed since the last time we
|
87 | // read from the store.
|
88 | if (checkIfSnapshotChanged(inst)) {
|
89 | // Force a re-render.
|
90 | forceUpdate({ inst: inst });
|
91 | }
|
92 | });
|
93 | // React Hook React.useEffect has a missing dependency: 'inst'. Either include it or remove the dependency array.
|
94 | // eslint-disable-next-line react-hooks/exhaustive-deps
|
95 | }, [subscribe]);
|
96 | return value;
|
97 | });
|
98 | function checkIfSnapshotChanged(_a) {
|
99 | var value = _a.value, getSnapshot = _a.getSnapshot;
|
100 | try {
|
101 | return value !== getSnapshot();
|
102 | }
|
103 | catch (_b) {
|
104 | return true;
|
105 | }
|
106 | }
|
107 | //# sourceMappingURL=useSyncExternalStore.js.map |
\ | No newline at end of file |