Background
我想了解Material UI对切换UI暗/亮模式主题的实现.Link.
我已经将其实现封装到一个自定义钩子中,在调用时返回与主题相关的属性.这是我的App()
级.
import { createContext, useState, useMemo } from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
export default function useTheme() {
const ColorModeContext = createContext({ toggleColorMode: () => {}, mode: null})
const [ mode, setMode ] = useState('light')
const colorMode = useMemo(
() => ({
toggleColorMode : () => {
setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'))
},
})
, [])
// recreate theme everytime mode changes
const appTheme = useMemo( () => (createTheme({
palette: {
mode: mode,
primary: ...
},
})), [mode])
return {
ColorModeContext,
colorMode,
ThemeProvider,
appTheme
}
}
在App()
级,我让它返回以下应用程序组件:
...
const {
ColorModeContext,
colorMode,
ThemeProvider,
appTheme
} = useTheme()
// another custom hook to return auth related properties
const {
AuthContext,
authed,
...
} = useAuth()
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={appTheme}>
<CssBaseline />
<AuthContext.Provider value=...>
<Box>
<Router>
<Header
ColorModeContext={ColorModeContext}
theme={appTheme}
authed={authed}
...
/>
<Routes>
<Route
path="/"
element={
<Signin AuthContext={AuthContext} />
}
/>
<Route
path="/create"
element={
<RequiredAuth authed={authed}>
<Create />
</RequiredAuth>
}
/>
<Route
path="/query"
element={
<RequiredAuth authed={authed}>
<Query />
</RequiredAuth>
}
/>
</Routes>
...
</Router>
</Box>
</AuthContext.Provider>
</ThemeProvider>
</ColorModeContext.Provider>
)
最后,在my header组件中(作为上下文使用者,在header中公开toggle回调函数)
...
const { ColorModeContext, authed, ... } = props;
return (
<ColorModeContext.Consumer>
{
({toggleColorMode}) => (
<Box>
<AppBar position="static" enableColorOnDark>
<Toolbar>
...
<IconButton
size="small"
onClick={toggleColorMode}
color="inherit"
>
{
theme.palette.mode === 'dark' ?
<LightModeIcon /> : <Brightness3Icon />
}
</IconButton>
...
</Toolbar>
</AppBar>
</Box>
)
}
</ColorModeContext.Consumer>
)
ISSUE
但是,如果我在组件<Create />
或<Query />
中切换主题,则整个组件树(创建或查询)将被重新装载,组件中的所有状态都将刷新到其初始状态.
基本上,如果我在我的<Create />
组件中,我正在填写创建表单,表单的值由useState
维护,只要我切换主题,所有的值都会重置为初始值(传递到useState
钩子中)
QUESTION
有没有办法防止这种重新装载的发生?我知道这不仅仅是重新招标组件,因为状态已经重新初始化.如果这不是重播的问题,那么React.memo
在这里行吗?如果不是,那么在子组件内部切换主题(父组件lvl的上下文)的最佳方式是什么,而无需重新安装组件.
添加codesandbox链接.它应该包括一个简单的例子,我的问题.当我切换父对象的主题模式时,子组件将重新装载(由子对象的useEffect
记录).