Improve handling of disconnected nodes in IntersectionObserver (#46156)

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

Changelog: [internal]

This improves the handling of disconnected nodes in `IntersectionObserver`. Specifically:
* When observing a node, if the node is disconnected (unmounted) this is just a no-op (without logging errors). We can't observe an unmounted node.
* When disconnecting the observer, if the observed nodes are disconnected, we get the target shadow node from an internal map, which we always have access to if we successfully started observing the node. If this logs an error now, it's something to look into but it won't generally log it if the target is just disconnected. That will work correctly.

Reviewed By: bvanderhoof

Differential Revision: D61656597

fbshipit-source-id: 6a39c878acc976ddc0789260106da104a3f2a57f
This commit is contained in:
Rubén Norte
2024-08-22 12:23:37 -07:00
committed by Facebook GitHub Bot
parent 5fc2bd4f60
commit 1f755defdc
2 changed files with 13 additions and 11 deletions
@@ -141,12 +141,14 @@ export default class IntersectionObserver {
return;
}
IntersectionObserverManager.observe({
const didStartObserving = IntersectionObserverManager.observe({
intersectionObserverId: this._getOrCreateIntersectionObserverId(),
target,
});
this._observationTargets.add(target);
if (didStartObserving) {
this._observationTargets.add(target);
}
}
/**
@@ -116,10 +116,10 @@ export function observe({
}: {
intersectionObserverId: IntersectionObserverId,
target: ReactNativeElement,
}): void {
}): boolean {
if (NativeIntersectionObserver == null) {
warnNoNativeIntersectionObserver();
return;
return false;
}
const registeredObserver = registeredIntersectionObservers.get(
@@ -129,15 +129,13 @@ export function observe({
console.error(
`IntersectionObserverManager: could not start observing target because IntersectionObserver with ID ${intersectionObserverId} was not registered.`,
);
return;
return false;
}
const targetShadowNode = getShadowNode(target);
if (targetShadowNode == null) {
console.error(
'IntersectionObserverManager: could not find reference to host node from target',
);
return;
// The target is disconnected. We can't observe it anymore.
return false;
}
const instanceHandle = getInstanceHandle(target);
@@ -145,7 +143,7 @@ export function observe({
console.error(
'IntersectionObserverManager: could not find reference to instance handle from target',
);
return;
return false;
}
// Store the mapping between the instance handle and the target so we can
@@ -160,11 +158,13 @@ export function observe({
isConnected = true;
}
return NativeIntersectionObserver.observe({
NativeIntersectionObserver.observe({
intersectionObserverId,
targetShadowNode,
thresholds: registeredObserver.observer.thresholds,
});
return true;
}
export function unobserve(