如何为条件渲染组件添加动画?React Motion UI Pack侧边导航问题
解决React Motion UI Pack侧边导航滑出动画不生效的问题
你的问题根源在于条件渲染直接卸载了Transition组件,导致离开动画根本没有执行的机会。React Motion UI Pack的Transition组件需要在状态切换时保持挂载(至少直到离开动画完成),不能通过isThere直接决定是否渲染它。下面是具体的解决方案:
核心思路
把侧边导航的显示/隐藏逻辑从「条件渲染组件」改为「用Transition的in属性控制动画状态」,让Transition始终存在于DOM中,通过in的布尔值触发进入/离开动画,动画完成后再处理后续状态(比如隐藏遮罩)。
修改后的完整代码示例
constructor(props){ super(props); // 初始状态根据窗口宽度自动判断是否打开侧边栏 this.state = { isOpen: window.innerWidth > this.props.breakWidth, showOverlay: false }; this.updatePredicate = this.updatePredicate.bind(this); this.handleToggleClick = this.handleToggleClick.bind(this); this.handleOverlayClick = this.handleOverlayClick.bind(this); this.handleLeaveComplete = this.handleLeaveComplete.bind(this); } componentDidMount() { this.updatePredicate(); window.addEventListener("resize", this.updatePredicate); } componentWillUnmount() { window.removeEventListener("resize", this.updatePredicate); } updatePredicate() { const shouldOpen = window.innerWidth > this.props.breakWidth; this.setState({ isOpen: shouldOpen, // 窗口宽度超过阈值时自动关闭遮罩 showOverlay: shouldOpen ? false : this.state.showOverlay }); } handleToggleClick(){ // 点击按钮时打开侧边栏并显示遮罩 this.setState({ isOpen: true, showOverlay: true }); } handleOverlayClick(){ // 点击遮罩仅触发关闭动画,遮罩在动画完成后再隐藏 this.setState({ isOpen: false }); } handleLeaveComplete(){ // 离开动画完成后关闭遮罩 this.setState({ showOverlay: false }); } render() { const { attributes, classes, Tag, src, href, children } = this.props; const sidenav = ( <Tag {...attributes} className={classes} key="sidenav"> <ul className="custom-scrollbar"> {src && ( <li> <div className="logo-wrapper"> <a href={href}> <img src={src} className="img-fluid"/> </a> </div> </li> )} {children} </ul> </Tag> ); return ( <div> {/* 始终渲染Transition,用in属性控制动画触发 */} <Transition component={false} appear={{ opacity: 0.2, translateX: -300 }} enter={{ opacity: 1, translateX: 0 }} leave={{ opacity: 0.2, translateX: -300 }} in={this.state.isOpen} onLeaveComplete={this.handleLeaveComplete} > {sidenav} </Transition> {/* 仅在窗口宽度小于阈值时显示切换按钮 */} {window.innerWidth <= this.props.breakWidth && ( <Button color="primary" onClick={this.handleToggleClick} key="sideNavToggles">ClickMe</Button> )} {/* 遮罩仅在侧边栏打开且窗口宽度小于阈值时显示 */} {this.state.showOverlay && ( <div id="sidenav-overlay" onClick={this.handleOverlayClick} key="overlay"></div> )} </div> ); }
关键修改点说明
状态拆分与逻辑优化
- 用
isOpen替代原来的isThere,专门控制侧边栏的显示/动画状态,初始值根据窗口宽度自动设置 - 窗口大小变化时,自动同步
isOpen状态,同时避免干扰用户手动打开的遮罩状态
- 用
始终渲染Transition组件
- 不再用
isThere做条件渲染,让Transition始终存在,通过in={this.state.isOpen}控制动画的触发 - 当
isOpen从true变为false时,Transition会自动执行leave定义的动画,而不是直接卸载组件
- 不再用
遮罩状态同步
- 添加
onLeaveComplete回调,在离开动画完全结束后再隐藏遮罩,避免遮罩提前消失导致的体验断层 - 优化遮罩的显示条件,仅在窗口宽度小于阈值且侧边栏打开时显示(窗口宽度足够大时不需要遮罩)
- 添加
这样修改后,点击遮罩时就能看到完整的滑出动画了,同时保留了窗口大小变化时的自动适配逻辑。
内容的提问来源于stack exchange,提问作者Jakub Strebeyko
相关产品推荐
相关产品推荐

