You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next 13 App目录的根布局中使用Context?

在Next.js 13 App目录的RootLayout中使用Context设置全局主题样式

要在RootLayout中通过Context控制body的全局主题样式,核心是用客户端组件实现ThemeProvider(服务端组件无法使用React状态/Context),并在Provider内部监听主题变化来动态修改body的样式类。以下是具体实现步骤:

1. 实现ThemeProvider(客户端组件)

在hooks/theme.tsx中编写主题Context的Provider,内部管理主题状态并同步更新body类名:

'use client';

import { createContext, useContext, useState, useEffect, ReactNode } from 'react';

type Theme = 'light' | 'dark';

type ThemeContextType = {
  theme: Theme;
  toggleTheme: () => void;
};

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

export default function ThemeProvider({ children }: { children: ReactNode }) {
  // 初始化主题:优先从localStorage读取,默认浅色
  const [theme, setTheme] = useState<Theme>(() => {
    if (typeof window !== 'undefined') {
      return (localStorage.getItem('theme') as Theme) || 'light';
    }
    return 'light';
  });

  // 主题变化时更新body类名和localStorage
  useEffect(() => {
    const body = document.body;
    body.classList.remove('light-theme', 'dark-theme');
    body.classList.add(`${theme}-theme`);
    localStorage.setItem('theme', theme);
  }, [theme]);

  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// 自定义Hook,方便其他组件快速获取主题
export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme必须在ThemeProvider内部使用');
  }
  return context;
}

2. 在globals.css中定义主题样式

添加对应主题的body全局样式:

/* 浅色主题 */
.light-theme {
  background-color: #ffffff;
  color: #1a1a1a;
}

/* 深色主题 */
.dark-theme {
  background-color: #1a1a1a;
  color: #ffffff;
}

/* 保留原有全局样式 */

3. 在RootLayout中嵌套ThemeProvider

保持RootLayout为服务端组件(无需加'use client',确保metadata正常导出),将ThemeProvider嵌套在body内部包裹所有子组件:

import './globals.css';
import { Inter } from 'next/font/google';
import ThemeProvider from "./hooks/theme";
import CardsProvider from "./hooks/getCards";

const inter = Inter({ subsets: ['latin'] });

export const 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}>
        <ThemeProvider>
          <CardsProvider>
            {children}
          </CardsProvider>
        </ThemeProvider>
      </body>
    </html>
  );
}

额外:在其他组件中切换主题

如果需要在页面/组件中实现主题切换,直接导入useTheme Hook即可:

'use client';

import { useTheme } from '../hooks/theme';

export default function ThemeToggle() {
  const { theme, toggleTheme } = useTheme();
  return (
    <button onClick={toggleTheme}>
      切换到{theme === 'light' ? '深色' : '浅色'}主题
    </button>
  );
}

内容的提问来源于stack exchange,提问作者Kolom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 23:03:32