You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为React Router的<Switch>设置延迟以完成CSS过渡退出动画

解决React Router Switch与CSSTransition退出动画被覆盖的问题

我之前在做路由过渡动画的时候也踩过一模一样的坑,核心原因是<Switch>组件的特性——它会立即卸载不匹配的路由组件,完全不等退出动画执行完毕,导致旧组件的exit状态还没触发就被删掉了,新组件直接挂载上来,看起来就像退出动画被覆盖了。

问题分析

你原来的写法是把<Switch>整个包裹在一个<CSSTransition>里,当路由变化时:

  1. <Switch>会立刻替换掉旧的路由组件
  2. <CSSTransition>还没来得及捕获旧组件的exit事件,组件就已经被卸载了
  3. 最终只看到新组件的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:56:35