今日文章目錄
- 需求說明
- 過程紀錄
- 問題統整
- 重點筆記
- 參考資料
深淺主題色顏色配置。
export const theme = {
light: {
backgroundColor: '#eae0d0',
color: '#000',
},
dark: {
backgroundColor: '#001529',
color: '#fff',
},
};
建立新資料夾,用來存放 Context 資料。(你可以擁有多個 Context)
使用React.createContext()
方法來建立Context,並設定預設值。
const ThemeContext = React.createContext(theme.light);
export default ThemeContext;
使用 Context名稱.Provider
來規範 資料分享範圍。
(Provider 會寫入一個 value props)
/*
我希望所有component都用到,所以我在 App.js 使用:
ThemeContext.Provider 包住所有子component
*/
function App() {
return (
<ThemeContext.Provider value={theme.light}>
<Router>
<Switch>
{routes.map((item) => (
<Route
key={item.path}
exact={item.exact}
path={item.path}
>
{item.component}
</Route>
))}
</Switch>
</Router>
</ThemeContext.Provider>
);
}
子層 component 要取得 Context 資料:
/* 引入useContext方法 與 目標Context */
import { useContext } from 'react';
import ThemeContext from '../context';
function CategoryList(props) {
/* 變數存取 useContext(目標Context) */
const theme = useContext(ThemeContext);
return(
<div style={{backgroundColor: theme.backgroundColor, color: theme.color}}>
...
</div>
)
}
來解釋一下:const theme = useContext(ThemeContext);
useContext(ThemeContext)
: 接收React.createContext()
回傳的目標Context物件。ThemeContext: React.Context<{ backgroundColor: string; color: string;}>
useContext()
方法回傳的Context值。theme: { backgroundColor: string; color: string;}
這裡的變數theme收到的值,來自 Context.Provider
value props,也就是 theme.light
目前顯示效果:有成功套入theme.light
的指定色。
再來做深淺色主題切換
既然資料統一放在Context,修改資料的方法也統一放在Context吧!
在 Context.Provider
的所在元件位置,加入 useState()
,並把 {state, setState}
傳下去。
function App() {
const [themsState, setThemeState] = useState(theme.light);
return (
<ThemeContext.Provider value={{ themsState, setThemeState }}>
...
</ThemeContext.Provider>
);
}
子層 component 要取得 Context 資料:
const {state, setState} = useContext(ThemeContext);
點擊切換鈕改值:這裡使用 Antd - Switch
<Switch
style={{ marginTop: 10 }}
checkedChildren="深色主題"
unCheckedChildren="淺色主題"
defaultChecked
onChange={() => {
setThemeState((pre) => (pre === theme.light ? theme.dark : theme.light));
}}
/>
實現效果:
A : useContext(MyContext) 只能讓你讀取 context 及訂閱其變更
。你仍然需要在 tree 的上層使用<MyContext.Provider> 來提供 context 的值。
A : 預設值被使用的時機是當開發者沒有使用 <Context.Provider> 卻又使用了 useContext 去取值時會用到;一旦使用 Context.Provider 後,就會以 <Context.Provider value={} />
中 value 帶入的值為主。
直接來驗證:
Context initialValue 為 theme.light
,Context.Provider value props 為 theme.dark
的情況
A : 離該component最接近的 Context.Provider value props
All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.
這裡也說明了不要濫用
useContext
的原因,當 Context更新,所有範圍內的子層都會 re-render,如果各種資料都往 Context 塞,將會造成效能問題。
Only use it for low-frequency updates like the theme and authentication. This is because whenever the context’s value changes, the descendant components of the Provider will be re-rendered.
Context uses reference identity to determine when to re-render.
useContext — This hook takes in a context object and returns whatever is passed in as a value prop in MyContext.Provider .