在useAnimatedGestureHandler中调用useState的set函数致应用崩溃,求解决
问题描述
在useAnimatedGestureHandler的onEnd事件中调用useState的set函数时应用崩溃,代码示例如下:
const [canTouch, setCanTouch] = useState(true); const unlockGestureSwipeUp = useAnimatedGestureHandler({ onStart: () => {}, onActive: (event) => { yUp.value = event.absoluteY; }, onEnd: (event) => { if (opacity1.value === 1 && (yUp.value < 600 || event.velocityY < -500)) { setCanTouch(false); opacity1.value = withDelay(0 * 500, withTiming(0, { duration: 1000 })); opacity2.value = withDelay(0 * 500, withTiming(1, { duration: 1000 })); // 其他代码... } }, });
每次执行到setCanTouch(false)时应用崩溃。
崩溃原因
useAnimatedGestureHandler的所有回调(包括onEnd)都运行在Reanimated专属的工作线程里,而useState的set函数是React主线程的API,直接在工作线程调用主线程的状态更新方法会造成线程上下文不匹配,直接引发崩溃。
另外补充:直接读取opacity1.value这类共享值的写法虽然不会直接导致崩溃,但在Reanimated的工作线程中,更规范的做法是遵循其状态管理逻辑,不过本次崩溃的核心原因还是跨线程调用React状态更新。
解决方法
方法1:用runOnJS包裹状态更新函数
Reanimated提供了runOnJS工具,专门用来把主线程的函数包装后在工作线程中调用,确保状态更新操作在React主线程执行:
import { runOnJS } from 'react-native-reanimated'; // ... const unlockGestureSwipeUp = useAnimatedGestureHandler({ // ...其他回调逻辑 onEnd: (event) => { if (opacity1.value === 1 && (yUp.value < 600 || event.velocityY < -500)) { // 通过runOnJS包裹setCanTouch,让它回到主线程执行 runOnJS(setCanTouch)(false); opacity1.value = withDelay(0 * 500, withTiming(0, { duration: 1000 })); opacity2.value = withDelay(0 * 500, withTiming(1, { duration: 1000 })); // 其他代码... } }, });
方法2:改用Reanimated的useSharedValue管理状态(推荐)
如果canTouch是用来控制动画相关的触摸交互,更推荐用Reanimated的SharedValue替代useState,这样全程在工作线程处理,彻底避免跨线程问题:
import { useSharedValue } from 'react-native-reanimated'; // 替换useState为useSharedValue const canTouch = useSharedValue(true); const unlockGestureSwipeUp = useAnimatedGestureHandler({ // ...其他回调逻辑 onEnd: (event) => { if (opacity1.value === 1 && (yUp.value < 600 || event.velocityY < -500)) { canTouch.value = false; // 直接修改共享值,无需跨线程 opacity1.value = withDelay(0 * 500, withTiming(0, { duration: 1000 })); opacity2.value = withDelay(0 * 500, withTiming(1, { duration: 1000 })); // 其他代码... } }, });
如果需要在React组件的JSX中使用canTouch的值,可以通过useDerivedValue或者runOnJS同步到主线程的useState状态中。
内容的提问来源于stack exchange,提问作者JGrima
相关产品推荐
相关产品推荐

