React Hook - useContext
useContext
是一个 React Hook,可以讀取和訂閱元件中的 context
const value = useContext(SomeContext);
基本概念與用法
useContext
可用於元件之間共享狀態,父層再也不需要透過 props 一層層傳狀態到子層,類似於任意門,適用於接收資料層與父層層級過多的狀況。
首先,先使用 createContext 創建一個 Context,在最上層使用 Context.provider
,並將要傳遞的資料放到 value,要接收資料的子層 component 可以透過 useContext 取得 values 的資料
// 建立一個 Context,預設值為 undefined
const AuthContext = React.createContext<Auth|undefined>(undefined);
// 父層使用 AuthContext.Provider
function App() {
return (
<AuthContext.Provider
value={{
id: 1234,
}}
>
<ChildComponent />
</ContextStore.Provider>
);
}
// 子層使用 useContext 拿到資料
function ChildComponent() {
const value = React.useContext(AuthContext);
return <span>value.id</span>;
}
透過 context 更新傳遞的數據
可以和 state 結合,將父層的狀態作為 context 值傳遞給 provider,倘若 id 值改變,則子層都會使用使用新的值來重新渲染
function App() {
const [id , setId] = useState(1234)
return (
<AuthContext.Provider
value={{id, setId}}
>
<ChildComponent />
<button onClick={()=> setId('2345')} >click</button>
</ContextStore.Provider>
);
}
要注意的是,useContext
可以有多個 provider ,但下層會覆蓋上層,如下面程式碼 App 和 ChildComponent 都使用了 userContext,但渲染時,它們分別會使用最接近它們的值,也就是説 App 使用 "User in App",而 ChildComponent 使用 "User in ChildComponent"
// UserContext.js
import { createContext } from "react";
export const UserContext = createContext();
// App.js
import React from "react";
import { UserContext } from "./UserContext";
function App() {
return (
<UserContext.Provider value="User in App">
<div>
<h1>App Component</h1>
<ChildComponent />
</div>
</UserContext.Provider>
);
}
// ChildComponent.js
import React from "react";
import { UserContext } from "./UserContext";
function ChildComponent() {
return (
<UserContext.Provider value="User in ChildComponent">
<div>
<h2>Child Component</h2>
</div>
</UserContext.Provider>
);
}
創建 useContext 的 custom hook
有時候忘記設定 provider 的 value,就會從 context 中得到 undefined,這時候可以透過創建一個 custom hook 來進行更好的錯誤處理
//useAuthContext
const AuthContext = React.createContext<Auth|undefined>(undefined);
function useAuthContext = ()=>{
const auth = React.useContext(AuthContext)
//當 context 拿到 undefined 時會跳出錯誤提醒
if(auth === undefined){
throw new Error('useAuthContext must be used with a AuthContext')
}
return auth
}
//component 中使用 useAuthContext
function ChildComponent() {
const value = useAuthContext();
return <span>value.id</span>;
}
useContext v.s Redux
useContext
主要目的是解決資料深層傳遞 props drilling 的問題;Redux
主要目的是協助狀態管理。雖然 useReducer 和 useContext 搭配可以達到類似 redux 的功能,但並不是原本的目的- 使用
useContext
,當值改變時,所有使用useContext
的元件都會重新渲染(未使用 useContext 的,不會重複渲染); redux 則是只有使用到改變值的元件才會重新渲染 useContext
可以有多個 provider,但下層會覆蓋掉上層,不會合併; redux 只有一個 store 且放在 root 層