Next.js中的脚本警告
我需要帮助,我在Next.js版本16中一直收到这个脚本警告。我正在尝试使用 next-themes 来实现浅色模式和深色模式。
## Error Type
Console Error
## Error Message
Encountered a script tag while rendering React component. Scripts inside React components are never executed when rendering on the client. Consider using template tag instead (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template).
at script (<anonymous>:null:null)
at ThemeProvider (src/components/ThemeProvider.jsx:7:10)
at RootLayout (src\app\layout.js:23:9)
## Code Frame
5 |
6 | export function ThemeProvider({ children, ...props }) {
> 7 | return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
| ^
8 | }
9 |
Next.js version: 16.2.6 (Turbopack)
这是我的 global.css,因为我正在使用 tailwind v4 来实现浅色模式和深色模式。
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700&display=swap');
@import "tailwindcss";
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
这是我的 layout.js
import { Nunito } from "next/font/google";
import { ThemeProvider } from "@/components/ThemeProvider";
import "./globals.css";
const nunito = Nunito({
subsets: ["latin"],
weight: ["400", "600", "700"],
});
export const metadata = {
title: "StoryMind",
description: "Stories & Summaries, powered by AI",
};
export default function RootLayout({ children }) {
return (
<html
lang="en"
suppressHydrationWarning
>
<body
className={`${nunito.className} antialiased h-full min-h-full flex flex-col`}>
<ThemeProvider
attribute="data-theme"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
<div id="modal-root"></div>
</ThemeProvider>
</body>
</html>
);
}
这是我的 ThemeProvider
"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({ children, ...props }) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}
解决方案
原理是:你的服务器不知道用户选择了哪种主题(这个信息保存在他们的浏览器中)。因此服务器会猜测为“浅色模式”。但是用户的浏览器显示为“深色模式”。现在React会报错,因为服务器输出的HTML与浏览器期望的不匹配。
"use client";
import Button from "@/components/ui/Button";
import { FiSun, FiMoon } from "react-icons/fi";
import { useTheme } from "next-themes";
import { useState, useEffect } from "react";
export default function ThemeToggle() {
const { resolvedTheme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setMounted(true);
}, []);
const toggleTheme = () => {
setTheme(resolvedTheme === "light" ? "dark" : "light");
};
// Render a placeholder with the same size so server and client agree
if (!mounted) {
return (
<div className="w-9 h-9" aria-hidden="true" />
);
}
return (
<Button
onClick={toggleTheme}
variant="other"
size="text-xl"
className="flex items-center justify-center p-2 transition-colors rounded-full w-9 h-9 hover:bg-muted"
aria-label={`Switch to ${resolvedTheme === "light" ? "dark" : "light"} mode`}
>
{resolvedTheme === "light" ? (
<FiMoon size={20} className="transition-colors text-muted-foreground hover:text-foreground" />
) : (
<FiSun size={20} className="transition-colors text-muted-foreground hover:text-foreground" />
)}
</Button>
);
}
修复Hydration不匹配:起初,服务器和浏览器渲染出的内容完全相同。没有不匹配。只有在页面完全加载后,才会切换到真实的图标。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。