From 1f755defdc0ac7b04f43f106e48b47a00566a66c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Thu, 22 Aug 2024 12:23:37 -0700 Subject: [PATCH] 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 --- .../IntersectionObserver.js | 6 ++++-- .../IntersectionObserverManager.js | 18 +++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserver.js b/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserver.js index 30a56756d46..1783adbc167 100644 --- a/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserver.js +++ b/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserver.js @@ -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); + } } /** diff --git a/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserverManager.js b/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserverManager.js index e15df994e35..d2d0067323c 100644 --- a/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserverManager.js +++ b/packages/react-native/src/private/webapis/intersectionobserver/IntersectionObserverManager.js @@ -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(