78 lines
2.4 KiB
JavaScript
78 lines
2.4 KiB
JavaScript
import {
|
|
useRef,
|
|
useEffect,
|
|
useMemo,
|
|
useDebugValue,
|
|
useSyncExternalStore
|
|
} from "react";
|
|
function isPolyfill(x, y) {
|
|
return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y;
|
|
}
|
|
const is = typeof Object.is === "function" ? Object.is : isPolyfill;
|
|
function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
|
|
const instRef = useRef(null);
|
|
let inst;
|
|
if (instRef.current === null) {
|
|
inst = {
|
|
hasValue: false,
|
|
value: null
|
|
};
|
|
instRef.current = inst;
|
|
} else {
|
|
inst = instRef.current;
|
|
}
|
|
const [getSelection, getServerSelection] = useMemo(() => {
|
|
let hasMemo = false;
|
|
let memoizedSnapshot;
|
|
let memoizedSelection;
|
|
const memoizedSelector = (nextSnapshot) => {
|
|
if (!hasMemo) {
|
|
hasMemo = true;
|
|
memoizedSnapshot = nextSnapshot;
|
|
const nextSelection2 = selector(nextSnapshot);
|
|
if (isEqual !== void 0) {
|
|
if (inst.hasValue) {
|
|
const currentSelection = inst.value;
|
|
if (isEqual(currentSelection, nextSelection2)) {
|
|
memoizedSelection = currentSelection;
|
|
return currentSelection;
|
|
}
|
|
}
|
|
}
|
|
memoizedSelection = nextSelection2;
|
|
return nextSelection2;
|
|
}
|
|
const prevSnapshot = memoizedSnapshot;
|
|
const prevSelection = memoizedSelection;
|
|
if (is(prevSnapshot, nextSnapshot)) {
|
|
return prevSelection;
|
|
}
|
|
const nextSelection = selector(nextSnapshot);
|
|
if (isEqual !== void 0 && isEqual(prevSelection, nextSelection)) {
|
|
return prevSelection;
|
|
}
|
|
memoizedSnapshot = nextSnapshot;
|
|
memoizedSelection = nextSelection;
|
|
return nextSelection;
|
|
};
|
|
const maybeGetServerSnapshot = getServerSnapshot === void 0 ? null : getServerSnapshot;
|
|
const getSnapshotWithSelector = () => memoizedSelector(getSnapshot());
|
|
const getServerSnapshotWithSelector = maybeGetServerSnapshot === null ? void 0 : () => memoizedSelector(maybeGetServerSnapshot());
|
|
return [getSnapshotWithSelector, getServerSnapshotWithSelector];
|
|
}, [getSnapshot, getServerSnapshot, selector, isEqual]);
|
|
const value = useSyncExternalStore(
|
|
subscribe,
|
|
getSelection,
|
|
getServerSelection
|
|
);
|
|
useEffect(() => {
|
|
inst.hasValue = true;
|
|
inst.value = value;
|
|
}, [value]);
|
|
useDebugValue(value);
|
|
return value;
|
|
}
|
|
export {
|
|
useSyncExternalStoreWithSelector
|
|
};
|