Reanimated动画在组件卸载时如何正确清理?

技术诗诗 阅读 85

我在用Reanimated 2实现按钮悬停缩放动画时遇到问题,当点击按钮跳转页面时动画突然中断,页面闪了一下。尝试在useEffect的清理函数里调用stopAnimation,但报错说animatedValue不是共享值。这是我的代码:


import { Animated, useSharedValue, useAnimatedReaction } from 'react-native-reanimated';

const Button = () => {
  const scale = useSharedValue(1);
  
  useAnimatedReaction(
    () => scale.value,
    (newScale) => {
      Animated.spring(scale, { toValue: newScale }).start();
    }
  );

  useEffect(() => {
    return () => {
      scale.stopAnimation(); // 这里报错
    };
  }, []);

  return (
    
      点击跳转
    
  );
};

查文档说要用useAnimatedProps,但不确定怎么改才能让动画在组件卸载时平滑停止。有没有更好的清理方式?

我来解答 赞 14 收藏
二维码
手机扫码查看
1 条解答
培培~
培培~ Lv1
你这个问题是典型的 Reanimated 2 在组件卸载时动画清理不当导致的。stopAnimation 确实不能直接用在 useSharedValue 上,因为它是针对旧版动画系统的 API。这里给你一个正确的解决方法。

一般这样处理:用 withTimingwithSpring 来代替 Animated.spring,并且通过 runOnJS 来确保清理函数在 JS 环境中执行。另外,你可以直接在 useEffect 的清理函数里重置 scale.value,这样就能避免动画突然中断的问题。

以下是修改后的代码:

import { useSharedValue, withSpring, useAnimatedStyle, runOnJS } from 'react-native-reanimated';

const Button = () => {
const scale = useSharedValue(1);

const animatedStyles = useAnimatedStyle(() => {
return {
transform: [{ scale: scale.value }],
};
});

useEffect(() => {
return () => {
// 卸载时重置 scale 值,并确保在 JS 环境中运行
runOnJS(() => {
scale.value = 1;
})();
};
}, []);

const handlePressIn = () => {
scale.value = withSpring(1.2); // 缩放效果
};

const handlePressOut = () => {
scale.value = withSpring(1); // 恢复原状
};

return (
style={[animatedStyles, { width: 100, height: 100, backgroundColor: 'blue' }]}
onPressIn={handlePressIn}
onPressOut={handlePressOut}>
点击跳转

);
};


重点是:
1. 使用 withSpring 替代旧的 Animated.spring
2. 在 useEffect 清理函数里通过 runOnJS 安全地重置 scale.value
3. 不要用 stopAnimation,它已经过时了。

这样改之后,动画会在组件卸载时平滑停止,不会有闪屏或报错问题。试试看吧!
点赞 3
2026-01-29 18:02