Fix bug in IntersectionObserver (#44439)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/44439

Changelog: [internal]

(IntersectionObserver isn't enabled yet in OSS).

This fixes a bug in `IntersectionObserver` when observing the same target in multiple observers. In that case, the first time we `unobserve` we clean up some metadata that's shared across observers, and other observers observing the target have problems with the missing data.

This fixes the problem by removing the clean up, as the data structure backing this information is a `WeakMap` anyway, so it'll be cleaned up automatically eventually, and the stored data is very small.

Reviewed By: twobassdrum

Differential Revision: D57046864

fbshipit-source-id: b001cf1ae4f4c91b74b1ad487e01691d5f3be1ce
This commit is contained in:
Rubén Norte
2024-05-07 09:43:48 -07:00
committed by Facebook GitHub Bot
parent a23ae9c7f2
commit 024f3357bb
@@ -67,19 +67,11 @@ function setTargetForInstanceHandle(
instanceHandleToTargetMap.set(key, target);
}
function unsetTargetForInstanceHandle(instanceHandle: mixed): void {
// $FlowExpectedError[incompatible-type] instanceHandle is typed as mixed but we know it's an object and we need it to be to use it as a key in a WeakMap.
const key: interface {} = instanceHandle;
instanceHandleToTargetMap.delete(key);
}
// The mapping between ReactNativeElement and their corresponding shadow node
// also needs to be kept here because React removes the link when unmounting.
// We also keep the instance handle so we don't have to retrieve it again
// from the target to unobserve.
const targetToShadowNodeAndInstanceHandleMap: WeakMap<
const targetToShadowNodeMap: WeakMap<
ReactNativeElement,
[ReturnType<typeof getShadowNode>, mixed],
ReturnType<typeof getShadowNode>,
> = new WeakMap();
/**
@@ -163,12 +155,8 @@ export function observe({
// access it even after the instance handle has been unmounted.
setTargetForInstanceHandle(instanceHandle, target);
// Same for the mapping between the target and its shadow node
// and instance handle.
targetToShadowNodeAndInstanceHandleMap.set(target, [
targetShadowNode,
instanceHandle,
]);
// Same for the mapping between the target and its shadow node.
targetToShadowNodeMap.set(target, targetShadowNode);
if (!isConnected) {
NativeIntersectionObserver.connect(notifyIntersectionObservers);
@@ -201,26 +189,18 @@ export function unobserve(
return;
}
const targetShadowNodeAndInstanceHandle =
targetToShadowNodeAndInstanceHandleMap.get(target);
if (targetShadowNodeAndInstanceHandle == null) {
const targetShadowNode = targetToShadowNodeMap.get(target);
if (targetShadowNode == null) {
console.error(
'IntersectionObserverManager: could not find registration data for target',
);
return;
}
const [targetShadowNode, instanceHandle] = targetShadowNodeAndInstanceHandle;
NativeIntersectionObserver.unobserve(
intersectionObserverId,
targetShadowNode,
);
// We can guarantee we won't receive any more entries for this target,
// so we don't need to keep the mappings anymore.
unsetTargetForInstanceHandle(instanceHandle);
targetToShadowNodeAndInstanceHandleMap.delete(target);
}
/**