You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native类组件转函数组件及添加额外动画问题咨询

Hey there! Let's break down how to convert your class component to a functional one, fix the animation state issue, and cover how to handle multiple animations. I'll keep things straightforward since you're new to React Native.

1. Defining Animated State in Functional Components

You can't just use a plain const rotateValueHolder = new Animated.Value(0); here—every time your component re-renders (which happens often in React), this line would create a brand new Animated.Value, breaking your animation entirely.

Instead, use useRef to preserve the same Animated.Value across component renders. useRef stores a mutable value that doesn't trigger re-renders when updated, which is perfect for Animated values:

import { useRef } from 'react';

// Inside your functional component
const rotateValueHolder = useRef(new Animated.Value(0)).current;

Alternatively, you can access it via .current directly later if you prefer:

const rotateValueHolder = useRef(new Animated.Value(0));
// Then reference rotateValueHolder.current in your animations

2. Updating the Animation Start Function

Since Animated.Value is mutable (you don't need a setter like setState), you can pass it directly to Animated.timing just like you suspected! Here's how your updated start function will look:

const startImageRotateFunction = () => {
  Animated.loop(
    Animated.timing(rotateValueHolder, {
      toValue: 1,
      duration: 4000,
      easing: Easing.elastic(4),
      useNativeDriver: false,
    })
  ).start();
};

Quick note: I removed the opacity: 1 from the config—it doesn't belong here; that's a style property, not part of the timing animation configuration.

3. Handling Multiple Animations

Let's cover the three common scenarios you asked about:

Simultaneous Animations

Use Animated.parallel to run multiple animations at the same time. For example, let's add a scale animation alongside the rotation:

First, define another Animated value with useRef:

const scaleValueHolder = useRef(new Animated.Value(1)).current;

Then create a function that runs both animations together:

const startCombinedAnimations = () => {
  // Reset values to their starting state first
  rotateValueHolder.setValue(0);
  scaleValueHolder.setValue(1);

  Animated.parallel([
    Animated.loop(
      Animated.timing(rotateValueHolder, {
        toValue: 1,
        duration: 4000,
        easing: Easing.elastic(4),
        useNativeDriver: false,
      })
    ),
    Animated.loop(
      Animated.timing(scaleValueHolder, {
        toValue: 1.2,
        duration: 2000,
        easing: Easing.inOut(Easing.ease),
        useNativeDriver: false,
      })
    )
  ]).start();
};

Update your Animated.Image style to include the scale transform:

transform: [
  {
    rotate: rotateValueHolder.interpolate({
      inputRange: [0, 1],
      outputRange: ['0deg', '360deg'],
    })
  },
  { scale: scaleValueHolder }
]

Sequential Animations

Use Animated.sequence to run animations one after another. For example, first rotate once, then scale the image:

const startSequentialAnimations = () => {
  rotateValueHolder.setValue(0);
  scaleValueHolder.setValue(1);

  Animated.sequence([
    Animated.timing(rotateValueHolder, {
      toValue: 1,
      duration: 4000,
      easing: Easing.elastic(4),
      useNativeDriver: false,
    }),
    Animated.timing(scaleValueHolder, {
      toValue: 1.2,
      duration: 1000,
      easing: Easing.inOut(Easing.ease),
      useNativeDriver: false,
    })
  ]).start();
};

Independent Timings

You can control each animation separately—like starting one on component mount, and another on button press. For example:

import { useEffect } from 'react';

useEffect(() => {
  // Start scale animation automatically when the component loads
  Animated.loop(
    Animated.timing(scaleValueHolder, {
      toValue: 1.2,
      duration: 2000,
      easing: Easing.inOut(Easing.ease),
      useNativeDriver: false,
    })
  ).start();
}, []);

// The rotate animation still starts only when the button is pressed

Full Converted Functional Component

Here's your complete class component converted to a functional one, including the rotation animation and an example scale animation:

import React, { useRef } from 'react';
import {
  SafeAreaView,
  View,
  Animated,
  Easing,
  TouchableHighlight,
  Text,
} from 'react-native';

export default function App() {
  const rotateValueHolder = useRef(new Animated.Value(0)).current;
  const scaleValueHolder = useRef(new Animated.Value(1)).current;

  const startCombinedAnimations = () => {
    rotateValueHolder.setValue(0);
    scaleValueHolder.setValue(1);

    Animated.parallel([
      Animated.loop(
        Animated.timing(rotateValueHolder, {
          toValue: 1,
          duration: 4000,
          easing: Easing.elastic(4),
          useNativeDriver: false,
        })
      ),
      Animated.loop(
        Animated.timing(scaleValueHolder, {
          toValue: 1.2,
          duration: 2000,
          easing: Easing.inOut(Easing.ease),
          useNativeDriver: false,
        })
      )
    ]).start();
  };

  return (
    <SafeAreaView>
      <View style={{ marginTop: 50 }}>
        <Animated.Image
          style={{
            width: 200,
            height: 200,
            alignSelf: "center",
            transform: [
              {
                rotate: rotateValueHolder.interpolate({
                  inputRange: [0, 1],
                  outputRange: ['0deg', '360deg'],
                })
              },
              { scale: scaleValueHolder }
            ],
          }}
          source={{ uri: 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/old_logo.png' }}
        />
        <TouchableHighlight
          onPress={startCombinedAnimations}
          style={{ marginTop: 30 }}
        >
          <Text style={{ textAlign: "center", fontSize: 18 }}>
            START ANIMATIONS
          </Text>
        </TouchableHighlight>
      </View>
    </SafeAreaView>
  );
}

A quick performance tip: If you want to use useNativeDriver: true for smoother animations, make sure all transform properties you're animating are supported (rotation and scale are fully supported). Just note that when using the native driver, you may need to adjust interpolations to use radian values (like outputRange: ['0rad', '6.28rad'] instead of degrees) for rotation—test it out to see what works best!

内容的提问来源于stack exchange,提问作者JulesUK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 18:30:59