如何在 Next JS 中使用 .tsx 文件实现“useContext”?

问题描述 投票:0回答:1

我正在尝试使用 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>
    );
}
javascript reactjs next.js react-hooks react-context
1个回答
0
投票
  • 您不需要在钩子文件本身内添加
    'use client'
    ;只需从
    'use client'
    中删除
    @/providers/theme-context-provider.tsx
  • <ThemeContextProvider>
    必须在客户端组件中使用。要实现此目的,请创建一个名为
    ClientProviders
    的新组件,它包装
    <ThemeContextProvider>
    (在
    ClientProviders
    中包含“使用客户端”)。
  • @/app/page.tsx
    文件也应该是
    Client Component
    (包括
    'use client'
    ),因为它依赖于
    useThemeContext
© www.soinside.com 2019 - 2024. All rights reserved.