函数组件中处理PanResponder onPanResponderRelease事件的状态过时问题
问题原因
你遇到的是闭包陷阱:PanResponder在组件首次渲染时被创建并存在useRef中,它内部引用的props.onReleased是初始渲染时的版本——这个版本的函数闭包捕获的是父组件当时的状态(也就是初始值)。后续父组件状态更新时,onReleased会重新创建,但PanResponder始终持有旧的函数引用,导致调用时访问的永远是初始状态。
解决方案
方案一:用useMemo让PanResponder随回调更新
子组件中不再用useRef固定PanResponder,而是用useMemo把props.onReleased作为依赖,每次回调更新时重新创建PanResponder,确保拿到最新的函数引用。
子组件修改后代码
import { useMemo } from 'react'; // 其他必要导入(如Animated、PanResponder) const Joystick = (props) => { const pan = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current; const panResponder = useMemo(() => PanResponder.create({ onMoveShouldSetPanResponder: () => true, onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }]), onPanResponderRelease: () => { Animated.spring(pan, { toValue: { x: 0, y: 0 }, useNativeDriver: false, }).start(); props.onReleased(); // 此时调用的是最新的父组件回调 }, }), [props.onReleased, pan] // 依赖变化时重新生成PanResponder ); // 剩余组件渲染逻辑... };
父组件优化(可选但推荐)
用useCallback包裹onReleased,避免不必要的回调重建和PanResponder重新创建:
import { useCallback } from 'react'; const ParentComponent = () => { const [someState, setSomeState] = useState(initialValue); const onReleased = useCallback(() => { // 这里能访问到最新的someState if (someState === /* 你的判断条件 */) { // 执行业务逻辑 } }, [someState]); // 依赖状态变化时更新回调 return <Joystick onReleased={onReleased} />; };
方案二:用ref保存最新的回调函数
如果不想每次回调变化都重新创建PanResponder,可以在子组件中用ref实时保存最新的props.onReleased,PanResponder内部调用这个ref的当前值。
子组件修改后代码
import { useRef, useEffect } from 'react'; // 其他必要导入 const Joystick = (props) => { const pan = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current; const latestOnReleased = useRef(); // 每次渲染时更新ref,确保保存最新的回调 useEffect(() => { latestOnReleased.current = props.onReleased; }, [props.onReleased]); const panResponder = useRef( PanResponder.create({ onMoveShouldSetPanResponder: () => true, onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }]), onPanResponderRelease: () => { Animated.spring(pan, { toValue: { x: 0, y: 0 }, useNativeDriver: false, }).start(); latestOnReleased.current?.(); // 调用最新的父组件回调 }, }) ).current; // 剩余组件渲染逻辑... };
父组件同样推荐优化
const ParentComponent = () => { const [someState, setSomeState] = useState(initialValue); const onReleased = useCallback(() => { if (someState === /* 你的判断条件 */) { // 执行业务逻辑 } }, [someState]); return <Joystick onReleased={onReleased} />; };
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

