Reanimated 2:更新状态会导致 animatedProps 中的动画重置,尽管没有更改共享值

Posted

技术标签:

【中文标题】Reanimated 2:更新状态会导致 animatedProps 中的动画重置,尽管没有更改共享值【英文标题】:Reanimated 2: Updating a state causes animation in animatedProps to reset despite not changing the shared value 【发布时间】:2021-09-15 13:55:02 【问题描述】:

场景:我在屏幕上呈现了一个svg circle 和一个state。我也有两个按钮。 Change Size 按钮将圆的大小(共享值)从 50 更改为 100 或从 100 更改为 50。更改状态按钮将状态从“苹果”更改为“橙色”或“橙色”更改为“苹果”。 [注意:动画不以任何方式使用状态。我还在每次重新渲染时控制台记录size.value]

问题:一旦按下Change Size按钮,它会将圆圈从50变为100。现在如果你按下Change State按钮,它会改变状态,但它也会使虽然我们的日志显示共享值size.value 仍然是 100,但圆圈回到 50。

预期行为:预期圆的大小保持为 100,因为这是提供给圆的共享值。

代码

import React, useState, useEffect from 'react';
import  Text, View, Button from 'react-native';
import Animated, 
  useAnimatedProps,
  useSharedValue,
  withSpring,
 from 'react-native-reanimated';
import Svg, Circle from 'react-native-svg';

const App = () => 
  const [state, setState] = useState('apple');

  const size = useSharedValue(50);
  const animatedProps = useAnimatedProps(() => 
    return 
      r: size.value / 2,
    ;
  );
  const AnimatedCircle = Animated.createAnimatedComponent(Circle);

  useEffect(() => 
    console.log('size.value =', size.value);
  );

  return (
    <View style=flex: 1>
      <Svg height=100 width=100>
        <AnimatedCircle
          cx="50"
          cy="50"
          fill="green"
          animatedProps=animatedProps
        />
      </Svg>
      <Text>state</Text>
      <Button
        title="Change Size"
        onPress=() => 
          size.value = withSpring(size.value === 50 ? 100 : 50);
        
      />
      <Button
        title="Change State"
        onPress=() => 
          setState(state === 'apple' ? 'orange' : 'apple');
        
      />
    </View>
  );


export default App;

任何帮助将不胜感激????

【问题讨论】:

@UğurEren 就这么简单?非常感谢你,伙计。解决了。​​ 【参考方案1】:

只需将const AnimatedCircle = Animated.createAnimatedComponent(Circle); 移动到您的函数组件之外。因为,在每次渲染时,react 都会运行你的函数。由于 createAnimatedComponent 在你的函数体中,它也会重新运行,所以它会从头开始重新创建组件。但是您应该只创建一次组件。

import React, useState, useEffect from 'react';
import  Text, View, Button from 'react-native';
import Animated, 
  useAnimatedProps,
  useSharedValue,
  withSpring,
 from 'react-native-reanimated';
import Svg, Circle from 'react-native-svg';

const AnimatedCircle = Animated.createAnimatedComponent(Circle);

const App = () => 
  const [state, setState] = useState('apple');

  const size = useSharedValue(50);
  const animatedProps = useAnimatedProps(() => 
    return 
      r: size.value / 2,
    ;
  );

  useEffect(() => 
    console.log('size.value =', size.value);
  );

  return (
    <View style=flex: 1>
      <Svg height=100 width=100>
        <AnimatedCircle
          cx="50"
          cy="50"
          fill="green"
          animatedProps=animatedProps
        />
      </Svg>
      <Text>state</Text>
      <Button
        title="Change Size"
        onPress=() => 
          size.value = withSpring(size.value === 50 ? 100 : 50);
        
      />
      <Button
        title="Change State"
        onPress=() => 
          setState(state === 'apple' ? 'orange' : 'apple');
        
      />
    </View>
  );

【讨论】:

【参考方案2】:

在状态更新时,功能组件被重新渲染,局部变量值被重新初始化。与其将 UI 组件(Circle)保留在不需要状态的父组件中,我们可以将其移动到不同的组件并用React.memo 包装。 React.memo 仅在更新 props 时重新渲染包装的组件。在这种情况下,当状态更新时,ui 组件中的道具将保持不变并且不会重新渲染。 让我们将圆形组件代码移动到新组件。

import React, useState, useEffect from 'react';
import  Text, View, Button from 'react-native';
import Animated, 
  useAnimatedProps,
  useSharedValue,
  withSpring,
 from 'react-native-reanimated';
import Svg, Circle from 'react-native-svg';

const App = () => 
  const [state, setState] = useState('apple');
  const size = useSharedValue(50);

  useEffect(() => 
    console.log('size.value =', size.value);
  );

  return (
    <View style=flex: 1>
      
      <Text>state</Text>
enter code here
enter code here
      <CircleMemo size=size/>
      <Button
        title="Change Size"
        onPress=() => 
          size.value = withSpring(size.value === 50 ? 100 : 50);
        
      />
      <Button
        title="Change State"
        onPress=() => 
          setState(state === 'apple' ? 'orange' : 'apple');
        
      />
    </View>
  );


export default App;

现在用 React.memo 记忆 React 组件,这样它就不会在状态更新时重新渲染。

const CircleUI = (size)=>
      const animatedProps = useAnimatedProps(() => 
        return 
          r: size.value / 2,
        ;
      );
      const AnimatedCircle = Animated.createAnimatedComponent(Circle);
      return (
          <Svg height=100 width=100>
            <AnimatedCircle
              cx="50"
              cy="50"
              fill="green"
              animatedProps=animatedProps
            />
          </Svg>
     )
    
    
const CircleMemo = React.memo(CircleUI);

【讨论】:

以上是关于Reanimated 2:更新状态会导致 animatedProps 中的动画重置,尽管没有更改共享值的主要内容,如果未能解决你的问题,请参考以下文章

react-native-reanimated iOS 崩溃

React Native Reanimated 2 为 SVG 路径的长度设置动画

安装 Reanimated 2 后仍会收到警告“如果您想使用 Reanimated 2 那么...”

React Native reanimated 不适用于插值

Reanimated 2 不能使用具有直接值的 withSequence

构建失败,因为 react-native-reanimated