React CSSTransition切换页面时重复创建新页面并执行过渡问题排查
问题分析与修复方案
核心问题
你的实现存在两个关键错误,导致页面过渡行为异常:
错误地将
<Routes>整体包裹在<CSSTransition>内
React Router v6的<Routes>组件会根据location变化直接替换内部渲染的路由组件,旧页面会被立即卸载,<TransitionGroup>无法跟踪其退出动画。同时,这种结构会触发<CSSTransition>重复渲染新路由组件——因为location.key更新时,整个<Routes>会被重新挂载,导致新页面被创建两次。未让
<TransitionGroup>管理单个路由元素的进出<TransitionGroup>的设计目标是跟踪单个元素的挂载/卸载状态,从而执行过渡动画。而你让它包裹整个路由匹配容器<Routes>,违背了这个使用逻辑,无法实现新旧页面的平滑交替。
修复后的代码
调整结构,使用useRoutes获取当前匹配的单个路由元素,再交由<CSSTransition>和<TransitionGroup>管理:
import "./styles.css"; import "bootstrap/dist/css/bootstrap.min.css"; import { BrowserRouter, useLocation, useNavigate, useRoutes } from "react-router-dom"; import { TransitionGroup, CSSTransition } from "react-transition-group"; import { Nav, Navbar } from "react-bootstrap"; import Settings from "./Settings"; import TestPage from "./TestPage"; function App() { const location = useLocation(); const navigate = useNavigate(); // 通过useRoutes获取当前匹配的路由元素 const currentRouteElement = useRoutes([ { path: "/settings", element: <Settings /> }, { path: "/testPage", element: <TestPage /> }, ]); return ( <div className="App"> <Navbar collapseOnSelect expand="lg" bg="dark" variant="dark"> <Navbar.Brand href="#home">Blaa</Navbar.Brand> <Navbar.Toggle aria-controls="responsive-navbar-nav" /> <Navbar.Collapse id="responsive-navbar-nav"> <Nav className="mr-auto"> <Nav.Link onClick={() => navigate("/settings")}>Settings</Nav.Link> <Nav.Link onClick={() => navigate("/testPage")}>TestPage</Nav.Link> </Nav> </Navbar.Collapse> </Navbar> <TransitionGroup component={null}> <CSSTransition key={location.key} classNames="fade" timeout={3000}> {/* 仅渲染当前匹配的单个路由组件 */} {currentRouteElement} </CSSTransition> </TransitionGroup> </div> ); } const Root = () => ( <BrowserRouter basename={window.location.pathname.replace(/(/[^/]+)$/, "")}> <App /> </BrowserRouter> ); export default Root;
补充CSS要求
确保你的styles.css中包含完整的过渡类样式,保证动画正常执行:
.fade-enter { opacity: 0; } .fade-enter-active { opacity: 1; transition: opacity 3000ms ease-in; } .fade-exit { opacity: 1; } .fade-exit-active { opacity: 0; transition: opacity 3000ms ease-out; } .fade-exit-done { display: none; }
内容的提问来源于stack exchange,提问作者boiler
相关产品推荐
相关产品推荐

