in packages/recoil/hooks/Recoil_useRetain.js [41:98]
function useRetain_ACTUAL(toRetain: ToRetain): void {
const array = Array.isArray(toRetain) ? toRetain : [toRetain];
const retainables = array.map(a => (a instanceof RetentionZone ? a : a.key));
const storeRef = useStoreRef();
useEffect(() => {
if (!gkx('recoil_memory_managament_2020')) {
return;
}
const store = storeRef.current;
if (timeoutID.current && !isSSR) {
// Already performed a temporary retain on render, simply cancel the release
// of that temporary retain.
window.clearTimeout(timeoutID.current);
timeoutID.current = null;
} else {
for (const r of retainables) {
updateRetainCount(store, r, 1);
}
}
return () => {
for (const r of retainables) {
updateRetainCount(store, r, -1);
}
};
// eslint-disable-next-line fb-www/react-hooks-deps
}, [storeRef, ...retainables]);
// We want to retain if the component suspends. This is terrible but the Suspense
// API affords us no better option. If we suspend and never commit after some
// seconds, then release. The 'actual' retain/release in the effect above
// cancels this.
const timeoutID = useRef();
const previousRetainables = usePrevious(retainables);
if (
!isSSR &&
(previousRetainables === undefined ||
!shallowArrayEqual(previousRetainables, retainables))
) {
const store = storeRef.current;
for (const r of retainables) {
updateRetainCount(store, r, 1);
}
if (previousRetainables) {
for (const r of previousRetainables) {
updateRetainCount(store, r, -1);
}
}
if (timeoutID.current) {
window.clearTimeout(timeoutID.current);
}
timeoutID.current = window.setTimeout(() => {
timeoutID.current = null;
for (const r of retainables) {
updateRetainCount(store, r, -1);
}
}, SUSPENSE_TIMEOUT_MS);
}
}