如何为React Router的<Switch>设置延迟以完成CSS过渡退出动画
解决React Router Switch与CSSTransition退出动画被覆盖的问题
我之前在做路由过渡动画的时候也踩过一模一样的坑,核心原因是<Switch>组件的特性——它会立即卸载不匹配的路由组件,完全不等退出动画执行完毕,导致旧组件的exit状态还没触发就被删掉了,新组件直接挂载上来,看起来就像退出动画被覆盖了。
问题分析
你原来的写法是把<Switch>整个包裹在一个<CSSTransition>里,当路由变化时:
<Switch>会立刻替换掉旧的路由组件<CSSTransition>还没来得及捕获旧组件的exit事件,组件就已经被卸载了- 最终只看到新组件的enter动画,完全看不到退出效果
解决方案
我们需要调整结构,确保<CSSTransition>能完整监控组件的挂载/卸载周期,同时让新旧组件在动画期间重叠显示(避免布局跳动)。
1. 修改App.js结构
把<Switch>放在一个带绝对定位的容器里,再用<CSSTransition>包裹,同时确保<Switch>接收当前的location属性:
import React from 'react'; import { Route, NavLink, Switch, useLocation } from "react-router-dom"; import './App.css'; import './aboutme.css'; import Home from './Home'; import About from './About'; import { CSSTransition, TransitionGroup } from 'react-transition-group'; function App() { const location = useLocation(); return ( <div className="App"> <div className="nav"> <NavLink exact to="/" activeClassName="active">Home</NavLink> <NavLink to="/about" activeClassName="active">About Me</NavLink> </div> <TransitionGroup> <CSSTransition key={location.key} timeout={{ enter: 300, exit: 400 }} classNames="slide" > {/* 给容器加绝对定位,让新旧页面重叠 */} <div style={{ position: 'absolute', width: '100%', top: 0 }}> <Switch location={location}> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </Switch> </div> </CSSTransition> </TransitionGroup> </div> ); } export default App;
2. 统一CSS动画时间与timeout配置
你的CSS中slide-exit-active的transition时间是300ms,但CSSTransition的exit timeout是400ms,这会导致动画不同步。修改App.css,让transition时间和timeout保持一致:
.slide-enter { transform: translate3d(-100vw, 0, 0); background-color: #5a564c; width: 100vw; height: 100vh; } .slide-enter-active { background-color: #9e8949; transition: all 300ms; /* 和enter timeout一致 */ transform: translate3d(0vw, 0, 0); } .slide-exit { background-color: #9e8949; transform: translate3d(0vw, 0, 0); } .slide-exit-active { transform: translate3d(100vw, 0, 0); transition: all 400ms; /* 和exit timeout一致 */ }
为什么这样修改有效?
- 绝对定位的容器让新旧路由组件在动画期间重叠显示,不会互相挤走对方
<Switch>接收location属性后,会基于传入的location渲染,配合location.key让<TransitionGroup>正确识别路由变化,触发完整的enter/exit动画- 统一的时间配置确保动画和组件卸载时机完全同步
这样修改后,你点击导航链接时,旧页面会先执行退出动画,完成后再卸载,新页面同时执行进入动画,就能看到完整的过渡效果了。
内容的提问来源于stack exchange,提问作者Willy Gozum
相关产品推荐
相关产品推荐

