Material-UI Nextjs 集成主题切换

Material-UI Nextjs Integration Theme Toggle

我正在尝试重新创建 material-ui website.

的主题切换功能

我的 Github 回购:https://github.com/jonnyg23/flask-rest-ecommerce/tree/next-app-migration

到目前为止,我注意到 material-ui 的网站使用一个名为 paletteType 的 cookie 来存储客户的主题选择。我知道应该使用上下文提供程序来设置 cookie,但是,我的 nav-bar 实现在第二次单击我的主题切换按钮后更改主题时出现问题。

非常感谢任何帮助,谢谢。

CustomThemeProvider.js:

import React, { createContext, useState } from "react";
import { ThemeProvider } from "@material-ui/core/styles";
import getTheme from "../themes";
import Cookie from "js-cookie";

export const CustomThemeContext = createContext({
  // Set the default theme and setter.
  appTheme: "light",
  setTheme: null,
});

const CustomThemeProvider = ({ children, initialAppTheme }) => {
  // State to hold selected theme
  const [themeName, _setThemeName] = useState(initialAppTheme);

  // Retrieve theme object by theme name
  const theme = getTheme(themeName);

  // Wrap setThemeName to store new theme names as cookie.
  const setThemeName = (name) => {
    // console.log("CustomThemeProvider, SetThemeName", name);
    Cookie.set("appTheme", name);
    _setThemeName(name);
  };

  const contextValue = {
    appTheme: themeName,
    setTheme: setThemeName,
  };

  return (
      <CustomThemeContext.Provider value={contextValue}>
        <ThemeProvider theme={theme}>{children}</ThemeProvider>
      </CustomThemeContext.Provider>
  );
};

export default CustomThemeProvider;

_app.js:

import "../styles/globals.css";
import React, { useContext, useEffect } from "react";
import PropTypes from "prop-types";
import { useAuth0 } from "@auth0/auth0-react";
import Head from "next/head";
import { Provider as NextAuthProvider } from "next-auth/client";
import { makeStyles } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";

import Auth0ProviderWithHistory from "../auth/auth0-provider-with-history";
import CustomThemeProvider, {
  CustomThemeContext,
} from "../context/CustomThemeProvider";

export default function App({ Component, pageProps }) {
  // const { isLoading } = useAuth0();
  const ThemeContext = useContext(CustomThemeContext);

  useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector("#jss-server-side");
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);

  return (
    <React.Fragment>
      <Head>
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width"
        />
      </Head>
      <CustomThemeProvider initialAppTheme={ThemeContext.appTheme}>
        <Auth0ProviderWithHistory>
          <NextAuthProvider session={pageProps.session}>
            <CssBaseline />
            <Component {...pageProps} />
          </NextAuthProvider>
        </Auth0ProviderWithHistory>
      </CustomThemeProvider>
    </React.Fragment>
  );
}

App.propTypes = {
  Component: PropTypes.elementType.isRequired,
  pageProps: PropTypes.object.isRequired,
};

ThemeModeToggle.js:

import React, { useContext } from "react";
import { IconButton } from "@material-ui/core";
import { makeStyles } from "@material-ui/core/styles";
import Brightness5TwoToneIcon from "@material-ui/icons/Brightness5TwoTone";
import Brightness2TwoToneIcon from "@material-ui/icons/Brightness2TwoTone";
import { CustomThemeContext } from "../context/CustomThemeProvider";

const useStyles = makeStyles((theme) => ({
  light: {
    color: theme.palette.secondary.main,
  },
  dark: {
    color: theme.palette.secondary.main,
  },
}));

const ThemeModeToggle = ({ fontSize }) => {
  const classes = useStyles();
  const { appTheme, setTheme } = useContext(CustomThemeContext);
  // console.log("ThemeModeToggle", appTheme);

  const handleThemeChange = (appTheme, setTheme) => {
    if (appTheme === "light") {
      setTheme("dark");
    } else {
      setTheme("light");
    }
  };

  return (
    <IconButton onClick={() => handleThemeChange(appTheme, setTheme)}>
      {appTheme === "light" ? (
        <Brightness5TwoToneIcon fontSize={fontSize} className={classes.light} />
      ) : (
        <Brightness2TwoToneIcon fontSize={fontSize} className={classes.dark} />
      )}
    </IconButton>
  );
};

export default ThemeModeToggle;

已解决,我找到问题了!

事实证明,我的页面组件(例如 StorefrontIconAppBar 颜色必须显式添加 className={classes.NAME}style={{ backroundColor: theme.palette.primary.main }} 例如。这两种方法都显示在我的 nav-bar.js 文件中。

import React from "react";
import { AppBar, Grid, Container, Toolbar } from "@material-ui/core";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import StorefrontIcon from "@material-ui/icons/Storefront";

import MainNav from "./main-nav";
import AuthNav from "./auth-nav";
import ThemeModeToggle from "./ThemeModeToggle";
import { Desktop, SmallScreen } from "./Responsive";
import HamburgerMenu from "./HamburgerMenu";

const useStyles = makeStyles((theme) => ({
  root: {
    [theme.breakpoints.down("sm")]: {
      padding: 0,
    },
  },
  icon: {
    color: theme.palette.primary.contrastText,
  },
}));

const NavBar = () => {
  const classes = useStyles();
  const theme = useTheme();

  return (
    <AppBar
      position="static"
      elevation={3}
      style={{ backgroundColor: theme.palette.primary.main }}
    >
      <Toolbar>
        <Container className={classes.root}>
          <Grid container justify="center" alignItems="center" spacing={2}>
            <Desktop>
              <Grid item xs={1}>
                <StorefrontIcon fontSize="large" className={classes.icon} />
              </Grid>
              <Grid item xs={7}>
                <MainNav />
              </Grid>
              <Grid item xs={3}>
                <AuthNav />
              </Grid>
              <Grid item xs={1}>
                <ThemeModeToggle fontSize="large" />
              </Grid>
            </Desktop>
            <SmallScreen>
              <Grid item xs={2}>
                <StorefrontIcon fontSize="medium" className={classes.icon} />
              </Grid>
              <Grid container item xs={10} justify="flex-end">
                <HamburgerMenu />
              </Grid>
            </SmallScreen>
          </Grid>
        </Container>
      </Toolbar>
    </AppBar>
  );
};

export default NavBar;