useContext 範例:CustomTheme
使用 useContext 實作 useCustomTheme 紀錄。react.v18, material UI.v5, CustomThemeProvider
引言
使用 useContext 實作 useCustomTheme 紀錄。
源碼紀錄
/*
* To customize the theme: Dark mode with a custom palette
* 參考:[Dark mode with a custom palette](https://mui.com/material-ui/customization/dark-mode/#dark-mode-with-a-custom-palette)
* 參考:[Toggling color mode](https://mui.com/material-ui/customization/dark-mode/#toggling-color-mode)
*/
import type { ReactChild } from 'react'
import React, { useContext, useReducer } from 'react'
import { createTheme, ThemeProvider } from '@mui/material/styles'
import { zhTW } from '@mui/material/locale'
import { IconButton } from '@mui/material'
// CSS
import DarkIcon from '@mui/icons-material/Brightness4'
import WhiteIcon from '@mui/icons-material/Brightness7'
//-----------------------------------------------------------------------------
//## Resource
const whiteTheme = createTheme(
{
palette: {
primary: { main: '#BF4690' },
},
},
zhTW, // Locale text:Use the theme to configure the locale text globally.
);
const darkTheme = createTheme(
{
palette: {
mode: 'dark',
},
},
zhTW, // Locale text:Use the theme to configure the locale text globally.
);
//-----------------------------------------------------------------------------
//## useContext
//# first, create empty context, 建構時給與初始值以避免當掉。
const CustomThemeContext = React.createContext({
colorMode: 'white',
toggleColorMode: () => { }
});
export function useCustomTheme() {
return useContext(CustomThemeContext)
}
export const CustomThemeProvider = (props: { children: ReactChild }) => {
//# 真正共享的實體在此建立
const [colorMode, toggleColorMode] = useReducer((mode) => mode === 'white' ? 'dark' : 'white', 'white')
return (
<CustomThemeContext.Provider value={{ colorMode, toggleColorMode }}>
<ThemeProvider theme={colorMode === 'dark' ? darkTheme : whiteTheme}>
{props.children}
</ThemeProvider>
</CustomThemeContext.Provider>)
}
//=============================================================================
//## helper component
//# 用來切換 while/dark theme
export const ToggleBrightnessButton = () => {
const themeMode = useCustomTheme()
return (
<IconButton onClick={themeMode.toggleColorMode} color="inherit" >
{themeMode.colorMode === 'dark' ? <DarkIcon /> : <WhiteIcon />}
</IconButton>
)
}
應用:掛入 CustomThemeProvider
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom'
import store from './store/store'
import App from './App'
import reportWebVitals from './reportWebVitals'
import * as serviceWorkerRegistration from './serviceWorkerRegistration'
import { CustomThemeProvider } from 'hooks/useCustomTheme'
import { CacheProvider } from '@emotion/react'
import createCache from '@emotion/cache'
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href') as string
const root = createRoot(
document.getElementById('root') as HTMLElement
);
export const muiCache = createCache({
key: 'mui',
prepend: true,
});
root.render(
<React.StrictMode>
<Provider store={store}>
<CacheProvider value={muiCache}>
<BrowserRouter basename={baseUrl}>
<CustomThemeProvider> /* 掛入 CustomThemeProvider */
<App />
</CustomThemeProvider>
</BrowserRouter>
</CacheProvider>
</Provider>
</React.StrictMode>
);
serviceWorkerRegistration.unregister()
reportWebVitals()
應用:切換 while / dark theme
import React from 'react'
import { AppBar, Toolbar, Typography } from '@mui/material'
// hooks
import { ToggleBrightnessButton } from 'hooks/useCustomTheme'
// CSS icons
import AdbIcon from '@mui/icons-material/Adb'
export default function Banner() {
return (
<AppBar position="static">
<Toolbar>
<AdbIcon />
<Typography variant="h6">
My First React.v18 App
</Typography>
<ToggleBrightnessButton />
</Toolbar>
</AppBar>
)
}
EOF
Last updated