React Native中Reanimated call()内函数未随Props更新问题排查
嘿,这个问题我熟,是典型的闭包陷阱导致的!让我给你拆解下原因和解决办法:
问题原因:闭包陷阱导致的旧props引用
你遇到的核心问题是JavaScript闭包特性在React动画钩子中的体现:
useCode的依赖数组是[],这意味着它只会在组件第一次渲染时执行一次,生成对应的动画逻辑块。- 你在
block里调用的onEmojiPress和onEmojiLongPress,是组件初始渲染时创建的函数——这些函数会捕获当时的reactionsprops值。 - 当后续父组件更新
reactions时,虽然组件会重新渲染并生成新的回调函数(捕获最新reactions),但useCode因为依赖数组为空,不会重新执行,所以动画逻辑里还是引用着旧版本的函数,自然用的是旧的reactions值。
解决方案:让动画逻辑依赖最新的回调函数
我们需要从两个方面修改代码,确保回调始终引用最新props,同时让useCode感知到函数的更新:
1. 用useCallback和useMemo包裹依赖props的内容
首先,把reacted的计算改成useMemo缓存,确保它随依赖项更新;然后用useCallback包裹回调函数,让它们的引用随依赖的props/状态变化而更新:
// 用useMemo缓存reacted的计算结果,依赖变化时自动更新 const reacted = useMemo(() => { return reactions.find( (reaction) => (reaction.user ? reaction.user.id === loggedInUsersId : false) && reaction.emoji === emoji ); }, [reactions, loggedInUsersId, emoji]); // 用useCallback包裹回调函数,确保依赖更新时函数引用更新 const onEmojiPress = useCallback(async () => { console.log('Emoji Pressed'); console.log(reactions.length); if (reacted) { await giveUnReaction(itemId, emoji, reacted.id); } else { await giveReaction(itemId, emoji); } }, [reacted, giveUnReaction, giveReaction, itemId, emoji]); const onEmojiLongPress = useCallback(() => { console.log('Emoji long Pressed'); Vibration.vibrate(1); navigate(assets.strings.dashboard.feeds.reactantsPopup.NAME, { reactions, emoji, }); }, [reactions, emoji, navigate]);
2. 更新useCode的依赖数组
把useCode的依赖数组加上我们刚才用useCallback包裹的两个函数,这样当函数引用更新时,useCode会重新执行,生成新的动画逻辑块,确保调用的是最新的回调:
useCode( () => block([ cond( eq(longPressState, State.BEGAN), set(shouldScale, 1) ), cond( eq(longPressState, State.FAILED), call([], onEmojiPress) ), cond( or( eq(longPressState, State.CANCELLED), eq(longPressState, State.END), ), call([], onEmojiLongPress) ), ]), // 加上依赖,确保回调更新时重新生成动画逻辑 [longPressState, shouldScale, onEmojiPress, onEmojiLongPress] );
验证修改
修改后,当父组件更新reactions props时,reacted会重新计算,onEmojiPress和onEmojiLongPress会更新为引用最新reactions的版本,useCode也会随之更新动画逻辑,此时触发LongPress的状态回调时,就能拿到最新的reactions值了。
内容的提问来源于stack exchange,提问作者Sanu Kumar
相关产品推荐
相关产品推荐

