React Native Reanimated通过forwardRef传递useAnimatedGestureHandler失效咨询
问题原因及修复方案
该问题属于写法错误,并非React Native Reanimated库的缺陷,核心错误有两处:
- forwardRef接收的ref参数本身就是你在父组件传入的
handlerRef,不需要额外访问.handlerRef属性,原代码中ref?.handlerRef?.current属于多余的嵌套取值,实际直接取ref?.current即可。 - 你将两个子组件
UsingHandlerDirect、UsingHandlerForwardRef定义在了App组件内部,每次App重渲染都会重新生成这两个组件的构造函数,导致组件卸载重挂载,状态和事件绑定失效,需要将子组件提到App组件外部定义。
此外你原代码中的手势逻辑也存在小问题:直接给y.value赋值translationY会导致每次拖动时方块从初始位置0开始计算,需要配合ctx.startY承接上一次拖动结束的位置。
修正后的完整代码如下:
// 子组件提到App外部定义 const UsingHandlerDirect = ({ handler, animatedStyles }) => ( <PanGestureHandler onGestureEvent={handler} > <Animated.View style={[styles.blueBox, animatedStyles]} /> </PanGestureHandler> ) const UsingHandlerForwardRef = forwardRef(({animatedStyles}, ref) => ( // 去掉多余的handlerRef层级,直接取ref.current <PanGestureHandler onGestureEvent={ref?.current}> <Animated.View style={[styles.redBox, animatedStyles]} /> </PanGestureHandler> )); // 给forwardRef组件设置displayName便于调试 UsingHandlerForwardRef.displayName = 'UsingHandlerForwardRef'; const App = () => { const handlerRef = useAnimatedRef(); const y = useSharedValue(0); handlerRef.current = useAnimatedGestureHandler({ onStart: (_, ctx) => { ctx.startY = y.value; }, onActive: ({translationY}, ctx) => { // 修复拖动位置计算逻辑 y.value = ctx.startY + translationY; }, onEnd: () => {}, }); const animatedStyles = useAnimatedStyle(() => ({transform: [{translateY: withSpring(y.value)}]})); return ( <SafeAreaView> <View style={styles.container}> <UsingHandlerForwardRef ref={handlerRef} animatedStyles={animatedStyles}/> <UsingHandlerDirect handler={handlerRef.current} animatedStyles={animatedStyles}/> </View> </SafeAreaView> ); }
优化建议
实际上不需要用useAnimatedRef存储手势handler,直接将handler作为props传递给子组件是更简洁、更符合React规范的写法,forwardRef更适合需要传递DOM/原生组件引用的场景。
内容的提问来源于stack exchange,提问作者Thomas Dittmar
相关产品推荐
相关产品推荐

