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

React Native类组件转函数组件后旋转动画Toggle失效求助

解决React Native函数组件中图片交替旋转的Toggle逻辑问题

问题描述

将React Native类组件转换为函数组件时,替换图标为图片后仅首次点击能触发旋转,后续点击无反应,需修复Toggle逻辑,实现图片点击交替顺时针、逆时针旋转的效果。

原类组件代码

import React from 'react';
import { View, StyleSheet, Animated, Image, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';

const TabIcon = ({
  onPress,
  menuToggled
}) => {
  const logoStyles = [styles.logoStyle];
  if (menuToggled !== null) {
    const animation = new Animated.Value(menuToggled ? 0 : 1);

    Animated.timing(animation, {
      toValue: menuToggled ? 1 : 0,
      duration: 500,
      useNativeDriver: true
    }).start();

    const rotateInterpolate = animation.interpolate({
      inputRange: [0, 1],
      outputRange: ['0deg', '360deg']
    });
    const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };
    logoStyles.push(animatedStyles);
  }

  return (
    <TouchableOpacity
      style={styles.tabStyle}
      onPress={onPress}
    >
      <Animated.View style={logoStyles}>
        <Animated.Image
          style={styles.tinyLogo}
          source={{
            uri: 'https://reactnative.dev/img/tiny_logo.png',
          }}
        />
      </Animated.View>
    </TouchableOpacity>
  );
};
export default class App extends React.Component {
  state = {
    menuToggled: null
  }

  toggleMenu = () => {
    this.setState(prevState => {
      return { menuToggled: !prevState.menuToggled };
    });
  }

  render () {
    return (
      <View style={styles.container}>
        <TabIcon
          onPress={this.toggleMenu}
          menuToggled={this.state.menuToggled}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'white'
  },  
  tinyLogo: {
    width: 150,
    height: 150,
    borderRadius: 100,
    margin: 8,
  },
});

修改后的函数组件代码(存在问题)

import React, { useRef, useState } from "react";
import { View, StyleSheet, Animated, Image, TouchableOpacity, Easing } from 'react-native';
import Constants from 'expo-constants';

const App = () => {
const spinValue = useRef(new Animated.Value(0)).current;
const [menuToggled, setMenuToggled] = useState([null]);

 toggleMenu = () => {
    setMenuToggled(menuToggled === "null" ? "menuToggled" : "null");
  }

const Spinner = ({
  onPress,
  menuToggled
}) => {
  const logoStyles = [styles.logoStyle];
 
    const animation = new Animated.Value(0);

  const go = () => {
    Animated.timing(animation, {
      toValue: 1,
      duration: 1500,
       easing: Easing.elastic(1),
      useNativeDriver: true
    }).start();

  }

    const rotateInterpolate = animation.interpolate({
      inputRange: [0, 1],
      outputRange: ['0deg', '360deg']
    });
    const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };
    logoStyles.push(animatedStyles);
 

  return (
    <TouchableOpacity
     
      onPress={go}  
    >
      <Animated.View style={logoStyles}>
        <Animated.Image
          style={styles.tinyLogo}
          source={{
            uri: 'https://reactnative.dev/img/tiny_logo.png',
          }}
        />
      </Animated.View>
    </TouchableOpacity>
  );
};

  return (
  <View style={styles.container}>
        <Spinner
          onPress={toggleMenu} 
          menuToggled={menuToggled}
          
        />
        
      </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'white'
  },  
  tinyLogo: {
    width: 150,
    height: 150,
    borderRadius: 100,
    margin: 8,
  },
});

export default App;

修复方案及代码

问题分析

  1. 状态初始化错误:useState([null])将初始状态设为数组,后续状态判断逻辑混乱,应改为布尔值类型的初始状态null或false。
  2. Toggle逻辑错误:toggleMenu中用字符串"null"和"menuToggled"判断,不符合布尔值切换逻辑,应使用函数式更新切换布尔状态。
  3. 动画值未持久化:Spinner组件内每次渲染都创建新的Animated.Value,导致动画无法复用,需用useRef保存动画值。
  4. 点击事件未绑定状态切换:Spinner的TouchableOpacity仅调用go函数,未触发父组件的onPress切换状态,导致旋转方向无法交替。
  5. 旋转方向未区分:未根据menuToggled状态设置不同的旋转方向,无法实现交替顺逆时针旋转。

修复后的完整代码

import React, { useRef, useState } from "react";
import { View, StyleSheet, Animated, Image, TouchableOpacity, Easing } from 'react-native';

const App = () => {
  // 初始化布尔状态,控制旋转方向
  const [menuToggled, setMenuToggled] = useState(null);

  // 切换状态的函数,使用函数式更新确保获取最新状态
  const toggleMenu = () => {
    setMenuToggled(prev => !prev);
  };

  const Spinner = ({ onPress, menuToggled }) => {
    // 用useRef持久化动画值,避免每次渲染重置
    const animation = useRef(new Animated.Value(0)).current;

    const startAnimation = () => {
      // 先调用父组件的状态切换函数
      onPress();
      // 根据当前状态设置目标值和旋转方向
      const toValue = menuToggled ? 0 : 1;
      Animated.timing(animation, {
        toValue,
        duration: 1500,
        easing: Easing.elastic(1),
        useNativeDriver: true
      }).start();
    };

    // 根据menuToggled状态切换旋转方向:顺时针360deg / 逆时针-360deg
    const rotateInterpolate = animation.interpolate({
      inputRange: [0, 1],
      outputRange: menuToggled ? ['0deg', '-360deg'] : ['0deg', '360deg']
    });

    const animatedStyles = { transform: [{ rotate: rotateInterpolate }] };

    return (
      <TouchableOpacity onPress={startAnimation}>
        <Animated.View style={[styles.logoStyle, animatedStyles]}>
          <Animated.Image
            style={styles.tinyLogo}
            source={{
              uri: 'https://reactnative.dev/img/tiny_logo.png',
            }}
          />
        </Animated.View>
      </TouchableOpacity>
    );
  };

  return (
    <View style={styles.container}>
      <Spinner onPress={toggleMenu} menuToggled={menuToggled} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'white'
  },
  tinyLogo: {
    width: 150,
    height: 150,
    borderRadius: 100,
    margin: 8,
  },
});

export default App;

关键修改说明

  • 状态改为布尔值类型,通过setMenuToggled(prev => !prev)可靠切换状态。
  • 用useRef保存Animated.Value,确保组件渲染时动画值不会被重置。
  • 点击事件先触发状态切换,再根据最新状态执行对应方向的动画。
  • 通过menuToggled动态设置outputRange,实现顺时针/逆时针交替旋转。

内容的提问来源于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 21:15:37