react-router-dom v6.3 结合framer-motion实现路由切换过渡效果的问题咨询
解决React Router v6 + Framer Motion路由切换动画不生效的问题
我刚好处理过相同的场景,把React Router从v5升级到v6后,原来的路由过渡动画直接失效了,下面是我验证可行的解决方案:
核心问题分析
React Router v6的Routes组件要求直接子元素只能是Route,所以不能像v5那样把motion.div包在路由容器外面——那样所有页面共享同一个motion容器,自然只会在首次加载时触发一次动画。我们需要让每个路由页面都拥有独立的motion容器,这样切换时旧容器卸载触发exit动画,新容器挂载触发enter动画。
具体实现步骤
- 首先确保引入所需的API(注意v6里用
Navigate替代v5的Redirect):
import { Routes, Route, Navigate, useLocation } from 'react-router-dom'; import { AnimatePresence, motion } from 'framer-motion';
- 保留你原来的动画配置:
const pageVariants = { initial: { opacity: 0 }, in: { opacity: 1 }, out: { opacity: 0 } }; const pageTransition = { type: 'tween', ease: 'linear', duration: 0.5 };
- 在组件内获取当前
location,然后调整路由结构:
const YourApp = () => { const location = useLocation(); return ( <AnimatePresence mode="wait"> <PageLayout> {/* 必须把location传给Routes,让AnimatePresence能感知路由变化 */} <Routes location={location}> {/* 每个路由的element都用motion.div单独包裹 */} <Route path="/audit" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <Audit /> </motion.div> } /> <Route path="/smartx" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <SmartX /> </motion.div> } /> <Route path="/smartx/erc20" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <TokenGenerator /> </motion.div> } /> <Route path="/createAudit" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <PaymentStatus /> </motion.div> } /> <Route path="/faq" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <FAQ /> </motion.div> } /> <Route path="/support" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <Support /> </motion.div> } /> <Route path="/terms" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <Terms /> </motion.div> } /> <Route path="/policy" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <Policy /> </motion.div> } /> <Route path="/about" element={ <motion.div initial="initial" animate="in" exit="out" variants={pageVariants} transition={pageTransition} > <About /> </motion.div> } /> {/* v6用Navigate替代Redirect */} <Route path="/" element={<Navigate to="/audit" />} /> </Routes> </PageLayout> </AnimatePresence> ); };
关键细节说明
AnimatePresence的mode="wait":确保旧页面的退出动画完全结束后,再开始新页面的进入动画,避免页面切换时的动画重叠。- 给
Routes传入location:让AnimatePresence能够准确检测到路由路径的变化,从而触发对应的动画生命周期。 - 每个路由独立包裹
motion.div:这样每次路由切换时,旧的motion容器会被卸载(触发exit动画),新的容器挂载时触发initial和animate动画,完美复刻v5时的效果。
内容的提问来源于stack exchange,提问作者user18472307
相关产品推荐
相关产品推荐

