无需状态/Props实现react-transition-group Modal淡入淡出过渡
实现无Props/状态控制的Modal淡入淡出动画
你的核心需求是让Modal仅通过父组件是否渲染它来自动触发淡入/淡出,不需要传递任何控制状态或Props,这个需求其实可以通过调整react-transition-group的使用方式来实现,问题出在你当前把TransitionGroup放在了Modal组件内部——这会导致父组件移除Modal时,整个组件(包括内部的TransitionGroup)被立即卸载,根本没机会播放退出动画。
正确的实现思路
TransitionGroup的作用是监听它直接包裹的子元素的添加/移除,并自动为子元素内的CSSTransition触发进入/退出动画。所以我们需要把TransitionGroup移到父组件中,用来包裹Modal的条件渲染,而Modal组件只负责封装Portal和动画逻辑,不需要接收任何控制类Props。
完整代码示例
1. 父组件(负责控制Modal的渲染与否)
import { useState } from 'react'; import { TransitionGroup } from 'react-transition-group'; import Modal from './Modal'; function App() { // 这个状态只在父组件内部使用,不需要传递给Modal const [showModal, setShowModal] = useState(true); return ( <div className="app"> <button onClick={() => setShowModal(!showModal)}> 切换Modal显示 </button> {/* TransitionGroup必须直接包裹动态渲染的Modal */} <TransitionGroup> {/* 给Modal设置唯一key,确保TransitionGroup能识别它的添加/移除 */} {showModal && <Modal key="modal">这是Modal内容</Modal>} </TransitionGroup> </div> ); }
2. Modal组件(封装Portal和动画,无控制Props)
import Fade from './Fade'; import Portal from './Portal'; // 假设你已经实现了Portal组件 const Modal = ({ children, ...other }) => { return ( <Portal> {/* 直接用Fade包裹内容,不需要内部的TransitionGroup */} <Fade> <div className="modal-container" {...other}> {children} </div> </Fade> </Portal> ); }; export default Modal;
3. Fade组件(复用CSSTransition逻辑)
import { CSSTransition } from 'react-transition-group'; const Fade = ({ children, ...other }) => ( <CSSTransition {...other} timeout={500} classNames="fade" unmountOnExit // 动画结束后自动卸载DOM > {children} </CSSTransition> ); export default Fade;
4. 对应的CSS样式
.modal-container { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 2rem; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); } /* 淡入动画类 */ .fade-enter { opacity: 0; } .fade-enter-active { opacity: 1; transition: opacity 500ms ease-in; } /* 淡出动画类 */ .fade-exit { opacity: 1; } .fade-exit-active { opacity: 0; transition: opacity 500ms ease-out; }
为什么这样可行?
- 当父组件渲染
<Modal />时,TransitionGroup会检测到新子元素的添加,自动触发CSSTransition的进入动画,实现淡入效果。 - 当父组件停止渲染
<Modal />时,TransitionGroup不会立即移除Modal的DOM,而是触发CSSTransition的退出动画,等动画完成后才会真正卸载Modal,实现淡出效果。 - Modal组件本身不需要接收任何控制状态或Props,完全符合你的需求——父组件只需要决定是否渲染它即可。
关于旧版react-css-transition-group的差异
你提到旧版方案可行,是因为旧版的TransitionGroup会自动监听子组件的挂载/卸载生命周期,无需显式在父层包裹。而新版react-transition-group调整了设计,要求TransitionGroup必须直接包裹动态变化的子元素,才能正确捕获添加/移除事件,这就是你之前实现失效的原因。
内容的提问来源于stack exchange,提问作者Myles
相关产品推荐
相关产品推荐

