React Router v6与react-transition-group集成时退出动画异常
React Router v6 与 react-transition-group 路由切换时旧组件未卸载问题解决
问题分析
升级到react-router-dom@6.4.1后,路由切换时旧组件未被卸载,新组件叠加在上方,核心原因是:
- React Router v6的
<Routes>组件与v5的<Switch>行为不同,直接在TransitionGroup中嵌套<Routes>会导致每次路由切换时,新的<Routes>实例被创建,而旧的实例在退出动画期间仍持有旧location并渲染对应组件,两者同时存在于DOM中。 - 未正确控制路由元素的过渡逻辑,导致新旧组件的DOM节点未按预期替换。
解决方案
修改AnimatedSwitch.js,通过useRoutes获取当前匹配的路由元素,让TransitionGroup仅处理单个路由元素的进出过渡,而非整个<Routes>容器:
修改后的 AnimatedSwitch.js
import React from 'react'; import { useLocation, useRoutes } from 'react-router-dom'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; import './AnimatedSwitch.scss'; const AnimatedSwitch = ({ children }) => { const location = useLocation(); const timeout = { enter: 400, exit: 200 }; const direction = 'left'; // 使用useRoutes获取当前location匹配的路由组件 const currentRoute = useRoutes(children); return ( <TransitionGroup component="div" className="container"> <CSSTransition key={location.key} timeout={timeout} classNames="pageSlider" unmountOnExit > <div className={direction}> {currentRoute} </div> </CSSTransition> </TransitionGroup> ); }; export default AnimatedSwitch;
配套CSS调整(AnimatedSwitch.scss)
确保过渡元素使用绝对定位,避免新旧组件上下排列:
.container { position: relative; width: 100%; min-height: 100vh; /* 确保容器占满视口高度 */ } .pageSlider-enter { transform: translateX(100%); } .pageSlider-enter-active { transform: translateX(0); transition: transform 400ms ease-in-out; } .pageSlider-exit { transform: translateX(0); } .pageSlider-exit-active { transform: translateX(-100%); transition: transform 200ms ease-in-out; } /* 让过渡元素绝对定位,重叠在容器内 */ .pageSlider-enter > .direction, .pageSlider-exit > .direction { position: absolute; top: 0; left: 0; width: 100%; }
关键说明
- useRoutes的作用:替代
<Routes>直接渲染,精准获取当前location匹配的单个路由组件,确保TransitionGroup只处理单个元素的过渡逻辑。 - 定位控制:容器设置相对定位,过渡元素设置绝对定位,保证新旧组件在动画期间重叠,而非上下排列。
- unmountOnExit:保留该属性,确保退出动画完成后旧组件被彻底卸载,避免DOM冗余。
内容的提问来源于stack exchange,提问作者Mohit kumar
相关产品推荐
相关产品推荐

