use-sync-external-store-with-selector
Version:
This package is just the [useSyncExternalStoreWithSelector](https://github.com/facebook/react/blob/main/packages/use-sync-external-store/src/useSyncExternalStoreWithSelector.js) hook extracted from React's [shim for `useSyncExternalStore`](https://github.
59 lines (58 loc) • 2.42 kB
JavaScript
import { useDebugValue, useEffect, useMemo, useRef, useSyncExternalStore, } from 'react';
export function useSyncExternalStoreWithSelector(subscribe, getSnapshot, selector, getServerSnapshot, 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 nextSelection = selector(nextSnapshot);
if (isEqual !== undefined && inst.hasValue) {
const currentSelection = inst.value;
if (isEqual(currentSelection, nextSelection)) {
memoizedSelection = currentSelection;
return currentSelection;
}
}
memoizedSelection = nextSelection;
return nextSelection;
}
const prevSnapshot = memoizedSnapshot;
const prevSelection = memoizedSelection;
if (Object.is(prevSnapshot, nextSnapshot)) {
return prevSelection;
}
const nextSelection = selector(nextSnapshot);
if (isEqual?.(prevSelection, nextSelection)) {
memoizedSnapshot = nextSnapshot;
return prevSelection;
}
memoizedSnapshot = nextSnapshot;
memoizedSelection = nextSelection;
return nextSelection;
};
const getSnapshotWithSelector = () => memoizedSelector(getSnapshot());
const getServerSnapshotWithSelector = typeof getServerSnapshot === 'function'
? () => memoizedSelector(getServerSnapshot())
: undefined;
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;
}