我正在尝试使用 use context 方法在 Next JS 中使用 MUI 实现双主题(深色和浅色)。
它给了我这个错误:
⨯ src\app\page.tsx (6:50) @ useThemeContext
⨯ TypeError: (0 , _providers_theme_context_provider__WEBPACK_IMPORTED_MODULE_1__.useThemeContext) is not a function
at Home (./src/app/page.tsx:16:117)
at stringify (<anonymous>)
digest: "3545525166"
请帮我解决这个问题。
我的
@/theme/index.tsx
'use client';
import { createTheme, responsiveFontSizes } from '@mui/material/styles';
import { lightPalette, darkPalette } from './palette';
export const lightTheme = responsiveFontSizes(createTheme({
typography: {
fontFamily: 'var(--font-roboto)',
},
palette: lightPalette,
}));
export const darkTheme = responsiveFontSizes(createTheme({
typography: {
fontFamily: 'var(--font-roboto)',
},
palette: darkPalette
}));
我正在尝试通过在文件中实现来使用上下文提供程序方法
@/providers/theme-context-provider.tsx
:
// @/providers/theme-context-provider.tsx
'use client'; // Required for client-side hooks
import { createContext, useContext, useState, useMemo, useEffect, ReactNode } from 'react';
import { ThemeProvider, CssBaseline } from '@mui/material';
import { lightTheme, darkTheme } from '@/theme'; // Adjusted import path
// Define the shape of the context
interface ThemeContextType {
toggleTheme: () => void;
mode: 'light' | 'dark';
}
// Create a context to store theme-related information
const ThemeContext = createContext<ThemeContextType>({
toggleTheme: () => {},
mode: 'light', // Default value
});
// Custom hook to use the ThemeContext
export const useThemeContext = () => useContext(ThemeContext);
interface ThemeContextProviderProps {
children: ReactNode;
}
// Create the provider component that will wrap your app
export const ThemeContextProvider: React.FC<ThemeContextProviderProps> = ({ children }) => {
// Check for user's preferred color scheme
const prefersDarkMode = typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches;
const [mode, setMode] = useState<'light' | 'dark'>(prefersDarkMode ? 'dark' : 'light');
// Sync with system theme changes
useEffect(() => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = (e: MediaQueryListEvent) => setMode(e.matches ? 'dark' : 'light');
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}, []);
// Handle manual theme toggle
const toggleTheme = () => {
const newMode = mode === 'light' ? 'dark' : 'light';
setMode(newMode);
localStorage.setItem('theme', newMode); // Persist the theme in localStorage
};
// Memoize the current theme
const currentTheme = useMemo(() => (mode === 'light' ? lightTheme : darkTheme), [mode]);
return (
<ThemeContext.Provider value={{ toggleTheme, mode }}>
<ThemeProvider theme={currentTheme}>
<CssBaseline />
{children}
</ThemeProvider>
</ThemeContext.Provider>
);
};
我在
@/app/layout.tsx
中使用了这个提供商:
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter'
import { ThemeContextProvider } from "@/providers/theme-context-provider";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable}`}>
<AppRouterCacheProvider options={{ enableCssLayer: true }}>
<ThemeContextProvider>
{children}
</ThemeContextProvider>
</AppRouterCacheProvider>
</body>
</html>
);
}
但是当我尝试在我的
@/app/page.tsx
中使用此上下文时
// app/page.tsx
import { Box, Button, Typography } from "@mui/material";
import { useThemeContext } from "@/providers/theme-context-provider";
export default function Home() {
const { toggleTheme, mode } = useThemeContext();
return (
<Box padding={2}>
<Typography variant="h4" gutterBottom>
Hello, welcome to my Next.js app!
</Typography>
<Button variant="contained" color="primary">
HELLO
</Button>
<Button variant="contained" color="primary" onClick={toggleTheme}>
Toggle to {mode === 'light' ? 'Dark' : 'Light'} Mode
</Button>
</Box>
);
}
'use client'
;只需从 'use client'
中删除 @/providers/theme-context-provider.tsx
。<ThemeContextProvider>
必须在客户端组件中使用。要实现此目的,请创建一个名为 ClientProviders
的新组件,它包装 <ThemeContextProvider>
(在 ClientProviders
中包含“使用客户端”)。@/app/page.tsx
文件也应该是 Client Component
(包括 'use client'
),因为它依赖于 useThemeContext
。