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

问题描述

场景:我在屏幕上呈现了一个 svg circle一个 state。我也有两个按钮。 Change Size 按钮将圆圈的大小(共享值)从 50 更改为 100 或 100 更改为 50。更改状态按钮将状态从“apple”更改为“orange”或“orange”更改为“apple”。 [注意:动画不以任何方式使用状态。我也在每次重新渲染时控制台记录 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;

任何帮助将不胜感激?

解决方法

只需将 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>
  );
}