diff --git a/packages/react-native/Libraries/Animated/useAnimatedProps.js b/packages/react-native/Libraries/Animated/useAnimatedProps.js index 28086bedfa6..0b79eb12666 100644 --- a/packages/react-native/Libraries/Animated/useAnimatedProps.js +++ b/packages/react-native/Libraries/Animated/useAnimatedProps.js @@ -22,6 +22,7 @@ import AnimatedValue from './nodes/AnimatedValue'; import { useCallback, useEffect, + useInsertionEffect, useLayoutEffect, useMemo, useReducer, @@ -314,8 +315,8 @@ function useAnimatedPropsLifecycle_layoutEffects(node: AnimatedProps): void { * NOTE: unlike `useAnimatedPropsLifecycle_layoutEffects`, this version uses passive effects to setup animation graph. */ function useAnimatedPropsLifecycle_passiveEffects(node: AnimatedProps): void { - const prevNodeRef = useRef(null); - const isUnmountingRef = useRef(false); + const attachedNodeRef = + useRef(null); useEffect(() => { // It is ok for multiple components to call `flushQueue` because it noops @@ -324,43 +325,45 @@ function useAnimatedPropsLifecycle_passiveEffects(node: AnimatedProps): void { NativeAnimatedHelper.API.flushQueue(); }); - useEffect(() => { - isUnmountingRef.current = false; + useInsertionEffect(() => { return () => { - isUnmountingRef.current = true; + const attachedNode = attachedNodeRef.current; + if (attachedNode != null) { + const {node: prevNode, listener} = attachedNode; + // NOTE: Do not restore default values on unmount, see D18197735. + prevNode.__detach(); + listener?.remove(); + attachedNodeRef.current = null; + } }; }, []); useEffect(() => { - node.__attach(); - let drivenAnimationEndedListener: ?EventSubscription = null; + let prevAttachedNode = null; + if (attachedNodeRef.current !== node) { + node.__attach(); + prevAttachedNode = attachedNodeRef.current; + let listener: ?EventSubscription = null; - if (node.__isNative) { - drivenAnimationEndedListener = - NativeAnimatedHelper.nativeEventEmitter.addListener( + if (node.__isNative) { + listener = NativeAnimatedHelper.nativeEventEmitter.addListener( 'onUserDrivenAnimationEnded', data => { node.update(); }, ); + } + + attachedNodeRef.current = {node, listener}; } - if (prevNodeRef.current != null) { - const prevNode = prevNodeRef.current; + + if (prevAttachedNode != null) { + const {node: prevNode, listener} = prevAttachedNode; // TODO: Stop restoring default values (unless `reset` is called). prevNode.__restoreDefaultValues(); prevNode.__detach(); - prevNodeRef.current = null; + listener?.remove(); } - return () => { - if (isUnmountingRef.current) { - // NOTE: Do not restore default values on unmount, see D18197735. - node.__detach(); - } else { - prevNodeRef.current = node; - } - - drivenAnimationEndedListener?.remove(); - }; }, [node]); }