Material UI自定义Classic主题切换失效问题求助
问题
我用Material UI创建了dark、classic、light三种主题模式,在Home.js中通过按钮切换。Dark和Light按钮切换正常,但点击Classic按钮时应用崩溃,控制台报两个错误:
- MUI: The palette mode 'classic' is not supported.
- ERROR Cannot read properties of undefined (reading 'primary')
相关代码如下:
theme.js
import { createTheme } from "@mui/material"; import { createContext, useMemo, useState } from "react"; export const tokens = (mode) => ({ ...(mode === "dark" ? { // DARK MODE primary1: { 500: "#1E2230", }, primary2: { 500: "#171A25", }, primary3: { 500: "#242937", }, button: { main: "#3555FF", }, } : mode === "classic" ? { // CLASSIC MODE primary1: { 500: "#211839", }, primary2: { 500: "#150D29", }, primary3: { 500: "#211839", }, } : // LIGHT MODE { primary1: { 100: "#040507", 200: "#090a0e", 300: "#0d0e15", 400: "#12131c", 500: "#161823", 600: "#45464f", 700: "#73747b", 800: "#a2a3a7", 900: "#d0d1d3", }, primary2: { 100: "#06070a", 200: "#0c0e13", 300: "#12141d", 400: "#181b26", 500: "#1e2230", 600: "#4b4e59", 700: "#787a83", 800: "#a5a7ac", 900: "#d2d3d6", }, primary3: { 100: "#07080b", 200: "#0e1016", 300: "#161921", 400: "#1d212c", 500: "#242937", 600: "#50545f", 700: "#7c7f87", 800: "#a7a9af", 900: "#d3d4d7", }, }), }); const DARK_MODE_BACKGROUND = "#131017"; // const CLASSIC_MODE_BACKGROUND = "#16121C"; const CLASSIC_MODE_BACKGROUND = "red"; const LIGHT_MODE_BACKGROUND = "white"; export const themeSettings = (mode) => { const colors = tokens(mode); return { palette: { mode: mode, ...(mode === "dark" ? { primary: { main: colors.primary1[500], }, secondary: { main: colors.primary2[500], }, background: { default: DARK_MODE_BACKGROUND, }, } : mode === "classic" ? { primary: { main: colors.primary1[500], }, secondary: { main: colors.primary2[500], }, background: { default: CLASSIC_MODE_BACKGROUND, }, } : { primary: { main: colors.primary1[100], }, secondary: { main: colors.primary2[100], }, background: { default: LIGHT_MODE_BACKGROUND, }, }), }, }; }; // context for color mode export const ColorModeContext = createContext({ toggleColorMode: () => {}, }); export const useMode = () => { // set the mode const [mode, setMode] = useState("dark"); const colorMode = useMemo( () => ({ toggleColorMode: (mode) => { switch (mode) { case "dark": setMode("dark"); break; case "classic": setMode("classic"); break; case "light": default: setMode("light"); break; } }, }), [] ); const theme = useMemo(() => createTheme(themeSettings(mode)), [mode]); return [theme, colorMode, setMode]; };
Home.js
import { Button, Typography } from "@mui/material"; import React, { useContext } from "react"; import { ColorModeContext, tokens } from "../Theme"; import { useTheme } from "@emotion/react"; export default function Home() { const theme = useTheme(); const colors = tokens(theme.palette.mode); const colorMode = useContext(ColorModeContext); return ( <div> hi <Button onClick={() => colorMode.toggleColorMode("dark")} variant="contained" > Dark </Button> <Button onClick={() => colorMode.toggleColorMode("classic")} variant="contained" > Classic </Button> <Button onClick={() => colorMode.toggleColorMode("light")} variant="contained" > Light </Button> <Typography variant="h1" color="primary"></Typography> </div> ); }
问题原因
- MUI palette模式限制:Material UI的
palette.mode仅支持官方定义的dark和light两种值,自定义的classic不在支持范围内,触发第一个报错的同时会导致MUI内部主题逻辑异常。 - 主题字段缺失:Classic模式的
tokens中缺少button字段,而contained类型的Button组件会尝试读取theme.palette.button.main,该字段不存在时会抛出“读取undefined属性”的错误。
修复方案
步骤1:修正palette.mode的值
将Classic模式的palette.mode设为dark(因Classic属于深色系主题),规避MUI的模式校验,同时通过自定义颜色区分Classic和Dark模式。
步骤2:补全Classic模式的tokens字段
在Classic模式的tokens中添加button字段,确保组件能读取到所需颜色值。
修改后的关键代码片段
theme.js(修改部分)
// 补全Classic模式的button字段 export const tokens = (mode) => ({ ...(mode === "dark" ? { /* 原Dark模式代码不变 */ } : mode === "classic" ? { // CLASSIC MODE primary1: { 500: "#211839", }, primary2: { 500: "#150D29", }, primary3: { 500: "#211839", }, // 添加button字段,适配contained按钮 button: { main: "#6A4C93", // 自定义Classic模式按钮颜色 }, } : /* 原Light模式代码不变 */), }); // 修正Classic模式的palette.mode为dark export const themeSettings = (mode) => { const colors = tokens(mode); return { palette: { // 对classic模式使用dark作为基础mode mode: mode === "classic" ? "dark" : mode, ...(mode === "dark" ? { /* 原Dark模式代码不变 */ } : mode === "classic" ? { primary: { main: colors.primary1[500], }, secondary: { main: colors.primary2[500], }, background: { default: CLASSIC_MODE_BACKGROUND, }, } : /* 原Light模式代码不变 */), }, }; };
额外说明
- 若需完全自定义主题模式,可通过扩展MUI的主题类型支持自定义mode,适合TypeScript项目。
- 确保所有组件用到的主题字段在各模式的
tokens中均有定义,避免出现undefined读取错误。
内容的提问来源于stack exchange,提问作者Sachin
相关产品推荐
相关产品推荐

