Next.js 14 App Router Framer Motion退出动画异常及渲染问题求助
Next.js 14 App Router + Framer Motion 页面过渡动画问题解决
问题背景
在Next.js 14(App Router)中使用Framer Motion实现页面过渡时,仅进入动画生效,退出动画无效果。参考方案实现退出动画后,控制台出现「Warning: Detected multiple renderers concurrently rendering the same context provider」警告,且刷新后前几次页面切换会出现空白,后续才恢复正常。
问题原因
采用的HOC方案通过冻结LayoutRouterContext实现退出动画,但Next.js内部不允许同时渲染多个相同的上下文提供者,这会导致上下文冲突,引发渲染警告和页面空白问题。
解决方案
放弃自定义HOC的方式,直接利用Next.js App Router的template组件结合Framer Motion的AnimatePresence实现页面过渡,无需手动操作路由上下文,从根源避免冲突。
修改后的代码示例
1. 更新 app/layout.tsx
移除自定义的PageAnimatePresence组件,简化布局结构:
import Parallax from './components/Parallax'; import Preloader from './components/Preloader'; import { Theme } from '@radix-ui/themes'; ... export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={roboto.variable}> <Theme hasBackground={false} panelBackground='translucent' > <Parallax> {children} {/* 直接渲染children,过渡逻辑交给template处理 */} </Parallax> <Preloader /> </Theme> </body> </html> ); }
2. 重构 app/template.tsx
将过渡逻辑整合到template组件中,利用usePathname触发动画:
'use client'; import { motion, AnimatePresence } from 'framer-motion'; import { usePathname } from 'next/navigation'; import { ReactNode } from 'react'; interface Props { children: ReactNode; } const variants = { hidden: { opacity: 0, x: "100%", y: 0 }, enter: { opacity: 1, x: 0, y: 0 }, exit: { opacity: 0, x: "-100%", y: 0 } }; export default function Template({ children }: Props) { const pathname = usePathname(); return ( <AnimatePresence mode="wait"> <motion.main key={pathname} variants={variants} initial="hidden" exit="exit" animate="enter" transition={{ type: 'linear', duration: 0.2 }} > {children} </motion.main> </AnimatePresence> ); }
3. 删除冗余组件
移除app/components/HOC/FrozenRoute.tsx和app/components/HOC/PageAnimatePresence.tsx两个自定义组件,清理代码。
方案说明
- template组件特性:App Router的template是页面的共享容器,页面切换时旧页面的template会执行exit动画,新页面的template执行enter动画,无需额外处理上下文。
- AnimatePresence触发逻辑:通过
usePathname作为motion.main的key,路径变化时AnimatePresence能准确识别组件替换,触发完整的进出动画流程。 - 避免上下文冲突:完全移除对
LayoutRouterContext的手动操作,符合Next.js内部渲染机制,消除警告和空白问题。
内容的提问来源于stack exchange,提问作者Wood3001
相关产品推荐
相关产品推荐

