Next JS 13 App Router中AnimatePresence退出动画失效求助
Next.js 13 App Router 中 Framer Motion 退出动画无效的解决方案
问题描述
基于 Next.js 13 新 App Router 的项目中,使用 Framer Motion 的 AnimatePresence 组件时,页面进入动画正常触发,但退出动画完全无效。已尝试在 RootLayout 和 template.tsx 中配置 AnimatePresence mode="wait",但问题仍未解决。
项目目录结构
app - layout.tsx - page.tsx - projects -- project --- page.tsx
已尝试的操作
- 在
app/layout.tsx中包裹AnimatePresence:export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}> <AnimatePresence mode="wait">{children}</AnimatePresence> </body> </html> ); } - 为首页添加 motion 动画配置:
const Home = () => { return ( <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1, transition: { duration: 3 } }} exit={{ opacity: 0, transition: { duration: 5 } }} className="grid gap-4 grid-cols-[repeat(1,minmax(400px,_1fr))] grid-rows-[repeat(4,minmax(400px,_1fr))] items-center justify-center" > <Link href="/projects/project">project page</Link> </motion.div> ); }; - 为项目详情页添加相同逻辑的动画配置;
- 按照 Next.js 文档建议改用
app/template.tsx包裹AnimatePresence:const Template: FC<{ children: ReactNode }> = ({ children }) => { return ( <AnimatePresence mode="wait">{children}</AnimatePresence> ); };
解决方案
1. 必须使用 template.tsx 并声明为客户端组件
RootLayout 是持久化渲染的,不会随路由切换重新渲染,因此无法让 AnimatePresence 检测到页面组件的卸载。必须使用 template.tsx,且需要添加 'use client' 声明(因为 Framer Motion 是客户端组件):
'use client'; import { AnimatePresence } from 'framer-motion'; import { ReactNode } from 'react'; export default function Template({ children }: { children: ReactNode }) { return <AnimatePresence mode="wait">{children}</AnimatePresence>; }
2. 给每个页面的 motion 组件添加唯一 key
AnimatePresence 需要通过唯一 key 识别组件的挂载/卸载状态,可使用 usePathname() 获取当前路由路径作为 key:
'use client'; import { motion } from 'framer-motion'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; // 首页示例 export default function Home() { const pathname = usePathname(); return ( <motion.div key={pathname} initial={{ opacity: 0 }} animate={{ opacity: 1, transition: { duration: 3 } }} exit={{ opacity: 0, transition: { duration: 5 } }} className="grid gap-4 grid-cols-[repeat(1,minmax(400px,_1fr))] grid-rows-[repeat(4,minmax(400px,_1fr))] items-center justify-center" > <Link href="/projects/project">project page</Link> </motion.div> ); }
项目详情页同理,添加 key={pathname} 即可。
3. 确保所有使用 motion 的页面声明为客户端组件
所有包含 motion 组件的页面文件顶部必须添加 'use client',否则无法在客户端触发动画逻辑。
4. 验证版本兼容性
确保使用的 framer-motion 版本为 10.x 及以上,旧版本可能存在 Next.js 13 App Router 的兼容性问题。
内容的提问来源于stack exchange,提问作者Raffi
相关产品推荐
相关产品推荐

