React Router v6.4.1中使用AnimatePresence实现页面退出动画的问题
React Router v6.4.1 中 Framer Motion 退出动画失效的解决方法
React Router v6.4 引入的createBrowserRouter和RouterProvider新API,会导致外层包裹的AnimatePresence无法触发页面退出动画——因为RouterProvider是稳定的根组件,路由切换时它不会卸载,AnimatePresence监听不到页面组件的卸载动作,自然无法执行退出动画。
解决思路
把AnimatePresence移到路由内部,配合Outlet使用,让路由切换时触发包裹页面的容器组件重新挂载,从而让AnimatePresence检测到组件的卸载与挂载,执行对应的动画。
具体实现步骤
创建动画布局组件
这个组件会用AnimatePresence包裹Outlet,并通过当前路由的pathname作为key,确保路由切换时容器重新渲染:import { Outlet, useLocation } from 'react-router-dom'; import { AnimatePresence } from 'framer-motion'; const AnimatedLayout = () => { const location = useLocation(); return ( <AnimatePresence mode="wait"> <div key={location.pathname}> <Outlet /> </div> </AnimatePresence> ); }; export default AnimatedLayout;配置路由结构
将动画布局作为父路由的element,页面路由作为子路由嵌套其中:import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import AnimatedLayout from './AnimatedLayout'; import HomePage from './HomePage'; import AboutPage from './AboutPage'; const router = createBrowserRouter([ { path: '/', element: <AnimatedLayout />, children: [ { index: true, element: <HomePage /> }, { path: 'about', element: <AboutPage /> }, ], }, ]); function App() { return <RouterProvider router={router} />; } export default App;给页面组件添加动画属性
每个页面组件必须用motion组件包裹,并配置initial、animate、exit动画参数:import { motion } from 'framer-motion'; const HomePage = () => { return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -20 }} transition={{ duration: 0.4 }} > <h1>首页</h1> <p>这是首页内容</p> </motion.div> ); }; export default HomePage;
关键说明
mode="wait"会让AnimatePresence等待当前页面的退出动画完成后,再渲染新页面,避免动画重叠。- 必须为每个页面组件配置
exit属性,否则AnimatePresence不会触发退出动画。 - 用
location.pathname作为容器的key,是为了让路由切换时触发容器的重新挂载,让AnimatePresence识别到组件的变化。
内容的提问来源于stack exchange,提问作者TSTobias
相关产品推荐
相关产品推荐

