React Native Reanimated 3:父组件卸载时如何阻止子视图退出动画
解决方案
1. 动态控制退出动画的启用
给子组件传入父组件的显示状态,仅在卡片需要保留时启用exiting动画;当父组件触发卸载时,直接禁用退出动画,让组件立即卸载。
修改子组件:
const CardWithText = ({ isVisible }) => { const [shownText, setShownText] = useState('text1') const currentTimeout = useRef(0) useEffect(() => { if(!currentTimeout.current){ toggleText(); } return () => clearTimeout(currentTimeout.current) // 清理定时器防止内存泄漏 },[]) const toggleText = () => { setShownText(prev => prev === "text1" ? "text2" : "text1") currentTimeout.current = setTimeout(() => toggleText(), 2500) } return ( <View> <Animated.Text entering={FadeIn.duration(600).delay(1500)} // 仅在卡片可见时启用退出动画,卸载时直接禁用 exiting={isVisible ? FadeOut.duration(600).delay(1200) : undefined} key={"card-info-" + shownText} > {shownText} </Animated.Text> </View> ) }
父组件调用时传入状态:
{ showSection1 ? <CardWithText isVisible={showSection1}/> : <SomeOtherComponent/> }
2. 卸载时清理定时器并强制隐藏文本
在子组件的卸载钩子中清理切换文本的定时器,同时通过状态立即隐藏文本组件,避免触发退出动画。
修改子组件:
const CardWithText = () => { const [shownText, setShownText] = useState('text1') const currentTimeout = useRef(0) useEffect(() => { toggleText(); return () => { clearTimeout(currentTimeout.current) // 立即清空文本状态,让组件直接卸载 setShownText(null) } },[]) const toggleText = () => { setShownText(prev => prev === "text1" ? "text2" : "text1") currentTimeout.current = setTimeout(() => toggleText(), 2500) } return ( <View> {/* 只有文本存在时才渲染组件 */} {shownText && ( <Animated.Text entering={FadeIn.duration(600).delay(1500)} exiting={FadeOut.duration(600).delay(1200)} key={"card-info-" + shownText} > {shownText} </Animated.Text> )} </View> ) }
3. 改用手动控制的动画替代组件级entering/exiting
放弃Reanimated的组件级动画API,改用useAnimatedStyle手动控制透明度,这样可以在父组件卸载时直接将透明度设为0且不播放动画,实现立即卸载。
示例:
import { useAnimatedStyle, withTiming } from 'react-native-reanimated' const CardWithText = ({ isVisible }) => { const [shownText, setShownText] = useState('text1') const currentTimeout = useRef(0) // 手动控制透明度动画 const textStyle = useAnimatedStyle(() => { return { opacity: isVisible ? withTiming(1, { duration: 600, delay: 1500 }) // 初始淡入动画 : withTiming(0, { duration: 0 }) // 卸载时立即透明 } }, [isVisible]) useEffect(() => { if (isVisible) { toggleText(); } else { clearTimeout(currentTimeout.current) } return () => clearTimeout(currentTimeout.current) }, [isVisible]) const toggleText = () => { setShownText(prev => prev === "text1" ? "text2" : "text1") currentTimeout.current = setTimeout(() => toggleText(), 2500) } return ( <View> <Animated.Text style={textStyle}>{shownText}</Animated.Text> </View> ) }
内容的提问来源于stack exchange,提问作者marcusdel2112
相关产品推荐
相关产品推荐

