Skip to main content

React Context是什麼?

什麼是 React Context?

React Context 提供了一個方法,讓你可以在元件樹中「廣播」資料,讓任何位於該 Context 範圍內的元件都能存取這些資料,而不需要明確地透過 props 一層層傳遞。它的核心組成包括:

  1. Context 物件:使用 React.createContext() 創建,定義了一個資料的「容器」。

  2. Provider:Context 物件的提供者,負責將資料傳遞給元件樹中的子元件。

  3. ConsumeruseContext Hook:用來在元件中存取 Context 提供的資料。

什麼時候使用 React Context?

你應該在以下情況考慮使用 React Context:

  • 當多個元件需要存取相同的資料(例如使用者登入狀態、主題設定)。

  • 當你不想透過 props 一層層傳遞資料,特別是當元件樹很深時。

  • 當你需要一個簡單的全域狀態管理方案,且不需要引入像 Redux 這樣的大型狀態管理庫。

不建議的情況:

  • 如果只需要在相鄰的父子元件之間傳遞資料,直接用 props 會更簡單。

  • 如果應用程式規模非常大且狀態管理很複雜,可能需要考慮 Redux 或 Zustand 等狀態管理庫。

如何使用 React Context?

以下是一個完整的教學範例,展示如何使用 React Context 來共享使用者資訊。我們會逐步說明,並提供完整的 JavaScript 程式碼,讓你可以直接操作。

步驟 1:創建 Context

首先,使用 React.createContext() 創建一個 Context 物件。

// context/UserContext.js
import { createContext } from "react";

// 創建一個 Context 物件,初始值可以設為 null 或預設值
const UserContext = createContext(null);

export default UserContext;
  • createContext:創建一個 Context 物件,這個物件包含 Provider 和 Consumer。

  • 初始值(這裡是 null)只有在元件沒有被任何 Provider 包圍時才會被使用。

步驟 2:提供 Context(使用 Provider)

接下來,在應用程式的頂層元件中使用 Provider 來提供資料。Provider 的 value 屬性會決定哪些資料可以被子元件存取。

// App.js
import React, { useState } from "react";
import UserContext from "./context/UserContext";
import UserProfile from "./components/UserProfile";

function App() {
// 假設這是使用者的狀態
const [user, setUser] = useState({
name: "小明",
email: "xiaoming@example.com",
});

return (
// 使用 Provider 包圍子元件,並傳遞 value
<UserContext.Provider value={{ user, setUser }}>
<div>
<h1>React Context 範例</h1>
<UserProfile />
</div>
</UserContext.Provider>
);
}

export default App;
  • UserContext.Provider:將 user 和 setUser 傳遞給所有子元件。

  • value 屬性可以傳遞任何資料,這裡我們傳遞了一個物件,包含 user 狀態和更新狀態的 setUser 函數。

步驟 3:在子元件中使用 Context(使用 useContext Hook)

在子元件中,使用 useContext Hook 來存取 Context 提供的資料。

// components/UserProfile.js
import React, { useContext } from "react";
import UserContext from "../context/UserContext";

function UserProfile() {
// 使用 useContext 來取得 Context 的 value
const { user, setUser } = useContext(UserContext);

// 函數:更新使用者名稱
const handleNameChange = () => {
setUser({ ...user, name: "小華" });
};

return (
<div>
<h2>使用者資料</h2>
<p>姓名:{user.name}</p>
<p>電子郵件:{user.email}</p>
<button onClick={handleNameChange}>將姓名改為小華</button>
</div>
);
}

export default UserProfile;
  • useContext(UserContext):從 Context 中提取 user 和 setUser。

  • 這裡我們展示了如何讀取資料(user.nameuser.email)以及如何更新資料(透過 setUser)。

步驟 4:執行與測試

  1. 確保你的專案結構如下:

    src / context / UserContext.js;
    components / UserProfile.js;
    App.js;
  2. 啟動你的 React 應用程式(假設你已用 create-react-app 建立專案):

    npm start
  3. 開啟瀏覽器,你會看到:

    • 使用者的姓名和電子郵件顯示在頁面上。

    • 點擊「將姓名改為小華」按鈕,會更新姓名為「小華」,顯示 Context 的狀態更新功能正常。

完整的程式碼總覽

為了讓你更容易複製並操作,這裡將所有程式碼整理在一起:

// context/UserContext.js
import { createContext } from "react";

const UserContext = createContext(null);

export default UserContext;
// components/UserProfile.js
import React, { useContext } from "react";
import UserContext from "../context/UserContext";

function UserProfile() {
const { user, setUser } = useContext(UserContext);

const handleNameChange = () => {
setUser({ ...user, name: "小華" });
};

return (
<div>
<h2>使用者資料</h2>
<p>姓名:{user.name}</p>
<p>電子郵件:{user.email}</p>
<button onClick={handleNameChange}>將姓名改為小華</button>
</div>
);
}

export default UserProfile;
// App.js
import React, { useState } from "react";
import UserContext from "./context/UserContext";
import UserProfile from "./components/UserProfile";

function App() {
const [user, setUser] = useState({
name: "小明",
email: "xiaoming@example.com",
});

return (
<UserContext.Provider value={{ user, setUser }}>
<div>
<h1>React Context 範例</h1>
<UserProfile />
</div>
</UserContext.Provider>
);
}

export default App;

常見問題與注意事項

  1. 什麼時候不用 Context?

    • 如果你的資料只需要在父子元件之間傳遞,直接用 props 更簡單。

    • 如果你的應用程式規模很大,Context 的狀態更新可能會導致不必要的重新渲染,這時可以考慮其他狀態管理方案。

  2. 如何避免 Context 過度使用?

    • 只把真正需要全域共享的資料放入 Context,例如主題、使用者資訊。

    • 不要把所有狀態都丟進 Context,這樣會讓程式碼難以維護。

  3. 如何在多個 Context 中使用? 如果你有多個 Context,可以巢狀使用多個 Provider。例如:

    <ThemeContext.Provider value={theme}>
    <UserContext.Provider value={user}>
    <App />
    </UserContext.Provider>
    </ThemeContext.Provider>
  4. 使用 Consumer 代替 useContext 如果你不使用 Hook,可以用 Consumer 來存取 Context,但 useContext 更簡潔:

    <UserContext.Consumer>
    {({ user, setUser }) => (
    <div>
    <p>姓名:{user.name}</p>
    </div>
    )}
    </UserContext.Consumer>

總結

React Context 是一個強大且簡單的工具,用來解決 props drilling 的問題,讓你可以在元件樹中共享資料。透過 createContext、Provider 和 useContext,你可以輕鬆地管理全域狀態。