Skip to main content

[React] contextAPI

context 顧名思義是框架、背景的意思,他會在背景中包裹住其他元件(components),讓其他元件可以使用儲存在裡面的變數,或著是說整個背景的狀態,而透過useState儲存的狀態,我們也可以將 setter 傳到其他被包裹的元件來改變狀態。

常見的 context 儲存的類型包括 light/dark theme、users,這次的範例就以切換 light/dark theme 為例,來介紹 contextAPI。

codesandbox: https://codesandbox.io/s/usecontext-hr5h4y?file=/src/contexts/ThemeContext.jsx

createContext

首先,先建立 contexts 的資料夾,裡面再建立ThemeContext.jsx的檔案。 createContext裡面的物件為變數的基本狀態,後面會透過ThemeContext.provider來改變

export const ThemeContext = createContext({
name: "",
setName: () => null,
theme: "light",
toggleTheme: () => null,
});

Context.Provider

ThemeContext是剛建立的基本 context,這邊我們建立ThemeProvider元件會回傳<ThemeContext.Provider>value則是放進我們在這個元件建立好的狀態,對應到ThemeContext的變數。

這種元件又被稱為 alias component,他接受名為 children 的 props,然後傳回給包裹住的元件,也是 children,讓被包裹的原件可以使用到ThemeContext.Provider提供的變數。

export const ThemeProvider = ({ children }) => {
const [name, setName] = useState("");
const [theme, setTheme] = useState("light");
// theme預設為light, toggleTheme會改變他的狀態
const toggleTheme = () => {
theme === "light" ? setTheme("dark") : setTheme("light");
};
const value = { name, setName, theme, toggleTheme };
return (
<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
);
};

接著我們到 index.js,引入ThemeProvider包裹住 App 元件,使得所有在 App 元件內的元件都可以使用到ThemeProvider的變數。

import { ThemeProvider } from "./contexts/ThemeContext";

<ThemeProvider>
<App />
</ThemeProvider>;

useContext

我建立一個控制背景色的按鈕,使用useContext,傳入ThemeContext,然後解構賦值toggleTheme: toggleTheme,用來改變theme的狀態。

import { useContext } from "react";
import { ThemeContext } from "../contexts/ThemeContext";

const ThemeButton = () => {
const { toggleTheme } = useContext(ThemeContext);
return <button onClick={toggleTheme}>Swith theme</button>;
};

export default ThemeButton;

在 App.js 匯入 ThemeButton,點擊時,其中包裹住文字的<div>的 className 會隨著theme而改變。

import { useContext } from "react";
import ThemeButton from "./components/ThemeButton";
import { ThemeContext } from "./contexts/ThemeContext";
const { name, setName, theme } = useContext(ThemeContext);

<div className="App">
<div className={theme === "light" ? "light" : "dark"}>
<h1>Hello {name}</h1>
<input onChange={handleChange} type="text" name="name" value={name} />
<h2>Enter your name</h2>
</div>
<ThemeButton />
</div>;
.dark {
background: #000;
color: #fff;
}

.light {
background: #fff;
color: #000;
}

結論

contextAPI 可以幫助許多元件共用相同的狀態,就像是個背景。React 一開始入門比較常使用 props 進行傳遞,而當元件大於兩層或是子元件之間想要分享狀態,之前的做法是在最上層的元件(如:App.js)定義狀態,再一步步傳下去,contextAPI 可以用更為簡便的方法解決這個問題。值得一提的是,contextAPI 可以建立不只一個 context,讓狀態儲存更為清晰,在狀態有問題的時候也只要去建立 context 的地方除錯。

現在的 contextAPI 很常與 useReducer 一起使用,而也有另一派的人主要使用 redux 的工具來儲存資料。

參考資料