Material UI页面间主题持久化问题及解决方案
MUI 5.14.1 主题持久化报错:
theme.transitions.create is not a function 解决方案 在使用MUI 5.14.1时,若直接将主题实例存入localStorage以实现跨页面主题持久化,读取后作为useState初始值会触发theme.transitions.create is not a function错误。这是因为localStorage仅能存储可序列化的数据,直接存储主题实例会丢失其原型链上的方法(比如transitions.create)。
以下是两种可行的解决方案:
方案一:React Context 全局主题状态管理
通过Context在全局维护主题状态,仅存储主题的标识参数(如模式)而非完整实例,动态生成主题以保证方法完整性。
完整代码示例
// theme-context.js import { createContext, useContext, useState, useMemo } from 'react'; import { createTheme } from '@mui/material/styles'; const ThemeContext = createContext(); export const ThemeProvider = ({ children }) => { // 从localStorage读取主题模式 const [themeMode, setThemeMode] = useState(() => { return localStorage.getItem('themeMode') || 'light'; }); // 根据模式动态创建主题实例 const theme = useMemo(() => { return createTheme({ palette: { mode: themeMode, }, }); }, [themeMode]); const toggleTheme = () => { const newMode = themeMode === 'light' ? 'dark' : 'light'; setThemeMode(newMode); localStorage.setItem('themeMode', newMode); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); }; export const useThemeContext = () => useContext(ThemeContext);
在App中引入使用:
// App.jsx import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; import { ThemeProvider, useThemeContext } from './theme-context'; function AppContent() { const { theme, toggleTheme } = useThemeContext(); return ( <MuiThemeProvider theme={theme}> <CssBaseline /> <button onClick={toggleTheme}>切换主题</button> {/* 其他业务组件 */} </MuiThemeProvider> ); } export default function App() { return ( <ThemeProvider> <AppContent /> </ThemeProvider> ); }
方案二:优化localStorage存储逻辑
不存储完整主题实例,仅存储主题的可序列化配置参数,读取后用这些参数重新创建主题实例,确保方法不丢失。
完整代码示例
import { useState, useMemo } from 'react'; import { createTheme, ThemeProvider } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; function App() { // 从localStorage读取主题配置 const [themeConfig, setThemeConfig] = useState(() => { const saved = localStorage.getItem('themeConfig'); return saved ? JSON.parse(saved) : { palette: { mode: 'light' } }; }); // 基于配置生成主题实例 const theme = useMemo(() => createTheme(themeConfig), [themeConfig]); const toggleTheme = () => { const newMode = themeConfig.palette.mode === 'light' ? 'dark' : 'light'; const newConfig = { ...themeConfig, palette: { mode: newMode } }; setThemeConfig(newConfig); localStorage.setItem('themeConfig', JSON.stringify(newConfig)); }; return ( <ThemeProvider theme={theme}> <CssBaseline /> <button onClick={toggleTheme}>切换主题</button> {/* 其他业务组件 */} </ThemeProvider> ); } export default App;
内容的提问来源于stack exchange,提问作者Tony Schneider
相关产品推荐
相关产品推荐

