Class组件转Function组件:动画元素无法保持位置的问题
问题:Function组件动画结束后元素回到初始位置
我有一个可正常运行的Class组件,将其转换为Function组件后,图片完成移动动画无法停留在目标位置,会回到初始创建位置。以下是问题代码及修复方案:
问题原因分析
- Animated.Value未持久化:Function组件中
positionX/positionY直接声明,每次组件重渲染都会重新初始化,动画完成后一旦组件刷新,就会回到初始值0;而Class组件将这些值存在state中,生命周期内不会被重置。 - 状态更新依赖旧值:
addDog直接使用dogs数组拼接,多次点击时会因闭包捕获旧状态导致更新异常,新添加的元素可能无法正确渲染。 - 未传递外部样式:DogContainer未使用传入的
styleprops,硬编码bottom:125,与Class组件逻辑不一致。 - 缺少动画完成回调:原Class组件的
onComplete移除逻辑在Function组件中未实现。
修复后的Function组件代码
import React, { useState, useEffect, useRef } from 'react'; import { View, TouchableOpacity, Text, Animated, Image, Easing } from 'react-native'; // 假设width和dogImg已提前定义 let dogCount = 0; export default function App() { const [dogs, setDogs] = useState([]); const addDog = () => { // 使用函数式更新获取最新状态,避免闭包问题 setDogs(prevDogs => { const newDog = { id: dogCount, bottom: 125 }; dogCount++; return [...prevDogs, newDog]; }); }; const removeDog = (id) => { setDogs(prevDogs => prevDogs.filter(dog => dog.id !== id)); }; return ( <View style={styles.entirebottomsheet}> <View style={styles.container}> <TouchableOpacity onPress={addDog} style={styles.dogButton}> <Text>Dog</Text> </TouchableOpacity> {dogs.map(dog => ( <DogContainer key={dog.id} style={{ bottom: dog.bottom, position: 'absolute' }} onComplete={() => removeDog(dog.id)} /> ))} </View> </View> ); } function DogContainer({ style, onComplete }) { // 用useRef持久化Animated.Value,避免重渲染时重置 const positionX = useRef(new Animated.Value(0)).current; const positionY = useRef(new Animated.Value(0)).current; useEffect(() => { const animations = [ Animated.spring(positionX, { duration: 1000, toValue: width / 3, easing: Easing.ease, useNativeDriver: true, }), Animated.spring(positionY, { duration: 1000, toValue: -340, // 和Class组件保持一致的目标值 easing: Easing.ease, useNativeDriver: true, }) ]; // 并行执行动画,结束后调用回调 Animated.parallel(animations).start(() => { console.log('finish'); onComplete?.(); }); // 组件卸载时停止动画,避免内存泄漏 return () => { positionX.stopAnimation(); positionY.stopAnimation(); }; }, [positionX, positionY, onComplete]); return ( <Animated.View style={[ style, // 应用外部传入的样式 { transform: [{ translateX: positionX }, { translateY: positionY }], } ]} > <Image source={dogImg} style={{ width: 60, height: 60, borderRadius: 30 }} /> </Animated.View> ); } // 假设样式已定义 const styles = { entirebottomsheet: { /* 你的样式 */ }, container: { /* 你的样式 */ }, dogButton: { /* 你的样式 */ } };
关键修复点
useRef持久化动画值:确保组件重渲染时不会重置动画状态,保持动画后的位置。- 函数式状态更新:使用
setDogs(prevDogs => ...)获取最新状态,避免闭包导致的旧值问题。 - 传递并合并外部样式:DogContainer接收并应用传入的
styleprops,与Class组件逻辑对齐。 - 实现动画完成回调:用
Animated.parallel并行执行动画,结束后调用onComplete处理移除逻辑。 - 添加动画清理:组件卸载时停止动画,避免内存泄漏。
内容的提问来源于stack exchange,提问作者이수민
相关产品推荐
相关产品推荐

