Reanimated跨线程同步调用函数报错 useAnimatedGestureHandler的onEnd回调iOS运行异常
问题原因
useAnimatedGestureHandler的所有回调(onStart/onActive/onEnd)默认运行在UI线程,而setHeaderExpanded是React的状态更新方法,只能运行在JS线程,你直接在onEnd里调用跨线程的JS方法,就会触发这个报错。- 浏览器环境是单线程的,不存在UI/JS线程隔离,所以逻辑能跑通,iOS原生端有线程隔离就会报错。
修复方案
首先需要从reanimated包导入runOnJS工具,然后修改onEnd回调逻辑,把所有JS线程的方法调用都用runOnJS包裹:
// 顶部先导入runOnJS import { useSharedValue, useAnimatedStyle, useAnimatedGestureHandler, withTiming, runOnJS } from 'react-native-reanimated' // 修改onEnd回调 const resizeHeaderHeight = useAnimatedGestureHandler({ onStart: () => {}, onActive: (event) => { headerHeight.value = event.absoluteY }, onEnd: () => { if(headerHeight.value < 305) { headerHeight.value = withTiming(176, { duration: 500, }) // 把setHeaderExpanded包在runOnJS里 runOnJS(setHeaderExpanded)(false) } else { headerHeight.value = withTiming(416, { duration: 500, }) runOnJS(setHeaderExpanded)(true) } }, })
注意事项
- 不需要给onEnd加
'worklet'声明,useAnimatedGestureHandler的回调默认已经是worklet运行在UI线程 - 所有需要在UI线程回调里调用的非worklet方法(包括React状态更新、自定义JS函数等)都必须用
runOnJS包裹,调用格式是runOnJS(你的函数)(参数1, 参数2...),不要写成runOnJS(你的函数(参数)),后者还是会先在UI线程执行函数,依然报错。 - 如果后续还要在onEnd里加其他自定义JS逻辑,建议把逻辑抽成单独的JS函数,统一用runOnJS调用即可。
内容的提问来源于stack exchange,提问作者Nikulás Óskarsson
相关产品推荐
相关产品推荐

