昨天我們用useState、useEffect、react-bootstrap完成了todolist程式,不過在寫程式的過程中,會發現我們傳遞的props隨著功能的增加越變越多,而且有些props甚至傳了好幾層的component,這樣在管理state和props上略顯麻煩,尤其是當我們要做更大型專案時,更需要一個有效管理state和props的工具。這種時候,就可以使用useContext
來處理。
有時候,我們會需要props傳遞好幾層的component,即使中間的component不需要,為了傳到底層也不得不傳進去,這樣很麻煩,一旦傳遞的props數量變多,還容易忘記或出錯。
而useContext
可以妥善解決這個問題。useContext
是可以讓props跨元件共享的一個hooks,透過useContext
,需要跨層傳遞的props可以直接在component內取用,而不需要一直傳遞一直傳遞。
那要如何使用useContext
呢?大體來說,要先創建一個context object,再用context provider包裹並傳遞,要用的時候則是用useContext取值使用。
首先要先有一個context object,這個context object會先用createContext()
這個api建立。由於會在useContext中使用到,因此一般會將其export
出去:
export const myContext = createContext();
建立後的context object有兩個子元件:
以往多是使用Consumer
來接收props,由於hooks的出現,useContext
的方式也很常用。
在建立context object時,也可以定義預設值,當取用的component上方沒有Provider時,會取用到預設值。
export const myContext = createContext("default value");
建立好context object後,就需要使用Provider
把需要的props傳出去:
const ContextProvider = ({children}) => {
const theme = {
light: {
background:"white",
color: "black"
},
dark: {
background: "black",
color: "white"
}
}
// 需要傳入theme.dark
return (
<myContext.Provider value={theme.dark}>
{children}
</myContext.Provider>
)
}
其中,children
是要包裹進Provider
中的子元件,由於Provider
可以傳遞props進子元件,即使是巢狀元件也可以,因此通常會將它包在需用的最外層。
要注意的是,在Provider
外面取用不到傳入的value,只能取用到createContext
時設定的預設值。
接著要在component中取用context object的value(props),要使用useContext()
的函式來取值。在useContext()
中傳入之前建立的context object:
const Component3 = () => {
const theme = useContext(myContext);
return (
<div style={theme}>
<p>Hello, world</p>
</div>
)
}
這樣就能取到值,並將其傳入到需要使用的地方。如上面這個component3
,透過context的方式取用到最上層的theme.dark
,並將裡面的樣式object傳入style
裡,就能顯示出設定好的樣式。
有一點要注意:useContext
只會取用離自己最近Provider
的值,如果有兩個相同context object的Provider
,只會取最近這個component的Provider
。
useContext
相當好用,但有個缺點,就是每當context object的值變動(例如state更新),底下的所有component都會re-render一遍。因此,useContext
比較適合用在不常變動的值上,避免不斷re-render,影響效能。
此外,當今天有許多需要用到useContext
的值的時候,可以用好幾層不同主題的Provider
來包住主程式,實現關注點分離(Separation of concerns),方便維護程式碼。
參考資料
[React Hook 筆記] useContext
實現跨元件資料共享, useContext
Hooks API 參考
Context-React