Ale*_*iva 5 reactjs next.js framer-motion react-server-components
我正在尝试使用 Next.js v14 进行页面转换,但没有成功。
没有显示错误,动画只是不起作用。我猜这是因为它layout.tsx
是在服务器上呈现的。但我该如何解决呢?
我的layout.tsx
代码(根级别):
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Sidebar from "@/components/Sidebar";
import Breadcrumbs from "@/components/Breadcrumbs";
import Topbar from "@/components/Topbar";
import PageTransitionEffect from "@/components/PageTransitionEffect";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={`${inter.className} flex flex-col min-h-screen`}>
<Topbar />
<div className="bg-gray-800 text-gray-200 flex flex-grow overflow-x-hidden px-0">
<Sidebar />
<div className="flex-col mx-auto flex w-full py-6 px-4 sm:px-6 md:px-14">
<Breadcrumbs />
<PageTransitionEffect>{children}</PageTransitionEffect>
</div>
</div>
</body>
</html>
);
}
Run Code Online (Sandbox Code Playgroud)
我的PageTransitionEffect
组件代码:
"use client";
import { motion } from "framer-motion";
const PageTransitionEffect = ({ children }: { children: React.ReactNode }) => {
const variants = {
hidden: { opacity: 0, x: -200, y: 0 },
enter: { opacity: 1, x: 0, y: 0 },
exit: { opacity: 0, x: 0, y: -100 },
};
return (
<motion.div
initial="hidden"
animate="enter"
exit="exit"
variants={variants}
transition={{ type: "linear" }}
>
{children}
</motion.div>
);
};
export default PageTransitionEffect;
Run Code Online (Sandbox Code Playgroud)
编辑#1(警告消息):
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
at FrozenRouter (webpack-internal:///(ssr)/./src/components/PageTransitionEffect/index.tsx:21:70)
at div
at MotionComponent (webpack-internal:///(ssr)/./node_modules/framer-motion/dist/es/motion/index.mjs:49:65)
at PopChildMeasure (webpack-internal:///(ssr)/./node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs:13:1)
at PopChild (webpack-internal:///(ssr)/./node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs:33:21)
at PresenceChild (webpack-internal:///(ssr)/./node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs:15:26)
at AnimatePresence (webpack-internal:///(ssr)/./node_modules/framer-motion/dist/es/components/AnimatePresence/index.mjs:72:28)
at PageTransitionEffect (webpack-internal:///(ssr)/./src/components/PageTransitionEffect/index.tsx:49:33)
at div
at div
at body
at html
at RootLayout (webpack-internal:///(ssr)/./src/app/layout.tsx:21:23)
at Lazy
at RedirectErrorBoundary (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/redirect-boundary.js:71:9)
at RedirectBoundary (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/redirect-boundary.js:79:11)
at ReactDevOverlay (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:66:9)
at HotReload (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:298:11)
at Router (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/app-router.js:154:11)
at ErrorBoundaryHandler (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/error-boundary.js:99:9)
at ErrorBoundary (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/error-boundary.js:128:11)
at AppRouter (webpack-internal:///(ssr)/./node_modules/next/dist/client/components/app-router.js:426:13)
at Lazy
at Lazy
at C:\Projects\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:35:374733
at C:\Projects\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:35:374733
at ServerInsertedHTMLProvider (C:\Projects\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:38:23140)
Run Code Online (Sandbox Code Playgroud)
组件代码:
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";
import { LayoutRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime";
import { useContext, useRef } from "react";
function FrozenRouter(props: { children: React.ReactNode }) {
const context = useContext(LayoutRouterContext);
const frozen = useRef(context).current;
return (
<LayoutRouterContext.Provider value={frozen}>
{props.children}
</LayoutRouterContext.Provider>
);
}
const variants = {
hidden: { opacity: 0, x: -30, y: 0 },
enter: { opacity: 1, x: 0, y: 0 },
exit: { opacity: 0, x: -30, y: 0 },
};
const PageTransitionEffect = ({ children }: { children: React.ReactNode }) => {
// The `key` is tied to the url using the `usePathname` hook.
const key = usePathname();
return (
<AnimatePresence mode="popLayout">
<motion.div
key={key}
initial="hidden"
animate="enter"
exit="exit"
variants={variants}
transition={{ type: "linear", duration: 0.2, delay: 0.1 }}
>
<FrozenRouter>{children}</FrozenRouter>
</motion.div>
</AnimatePresence>
);
};
export default PageTransitionEffect;
Run Code Online (Sandbox Code Playgroud)
Ric*_*ico 13
目前存在一个由应用程序路由器和共享布局引起的错误,导致该错误无法正常工作。不过,有一个解决方法。除了解决方法之外,我们还需要 3 个其他东西:
AnimatePresence
来自成帧器运动(这有助于我们使用退出和进入动画)key
运动元素上的A触发重新渲染 (这会在页面更改时触发动画)mode='popLayout'
到AnimatePresence
(这会立即从树中删除旧页面。您可以使用模式值,不同的模式对于某些动画更好。)例子:
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { usePathname } from "next/navigation";
import { LayoutRouterContext } from "next/dist/shared/lib/app- router-context.shared-runtime";
import { useContext, useRef } from "react";
function FrozenRouter(props: { children: React.ReactNode }) {
const context = useContext(LayoutRouterContext ?? {});
const frozen = useRef(context).current;
return (
<LayoutRouterContext.Provider value={frozen}>
{props.children}
</LayoutRouterContext.Provider>
);
}
const variants = {
hidden: { opacity: 0, x: -200, y: 100 },
enter: { opacity: 1, x: 0, y: 0 },
exit: { opacity: 0, x: 0, y: -100 },
};
const PageTransitionEffect = ({ children }: { children: React.ReactNode }) => {
// The `key` is tied to the url using the `usePathname` hook.
const key = usePathname();
return (
<AnimatePresence mode="popLayout">
<motion.div
key={key}
initial="hidden"
animate="enter"
exit="exit"
variants={variants}
transition={{ type: "linear" }}
className="overflow-hidden"
>
<FrozenRouter>{children}</FrozenRouter>
</motion.div>
</AnimatePresence>
);
};
export default PageTransitionEffect;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2197 次 |
最近记录: |