React Context API 介紹
React Context API 介紹
React Context API 是一個強大的工具,用來在組件樹中共享狀態,而不必逐層傳遞 props
。它允許我們在父組件和任意深度的子組件之間共享數據,這對於全局狀態管理(如用戶信息、主題、語言設置等)非常有用。
Context API 的主要用途:
- 避免
props drilling
:在 React 中,當父組件需要將狀態傳遞給深層嵌套的子組件時,通常需要逐層傳遞props
。Context API 可以讓你直接在子組件中獲取父組件的狀態,而不需要經過中間層。 - 全局狀態共享:可以在應用的任何地方使用 Context,無需手動傳遞數據。
1. Context API 的基本結構
Context API 主要包括三個核心概念:
React.createContext()
:用來創建一個 Context 對象。<Context.Provider>
:用來提供數據,通過這個組件來傳遞數據給子組件。useContext()
或<Context.Consumer>
:用來在子組件中獲取上下文數據。
2. Context API 的使用步驟
(1) 創建 Context
首先,我們使用 React.createContext()
創建一個 Context,這將返回一個包含 Provider
和 Consumer
的對象。
1
2
3
4
import React from "react";
// 創建一個 Context
const MyContext = React.createContext();
(2) 提供數據(Provider)
在父組件中使用 Provider
包裹需要傳遞數據的組件樹,並將共享的數據傳遞給 Provider
的 value
屬性。
1
2
3
4
5
6
7
8
9
function App() {
const user = { name: "John", age: 30 };
return (
<MyContext.Provider value={user}>
<ChildComponent />
</MyContext.Provider>
);
}
在這個範例中,我們將 user
對象作為 value
傳遞給 MyContext.Provider
,這樣 ChildComponent
及其子組件就能夠訪問這個上下文數據。
(3) 使用數據(useContext 或 Consumer)
在子組件中,我們可以通過 useContext
Hook 或 Context.Consumer
獲取共享數據。
使用 useContext
Hook:
1
2
3
4
5
6
7
8
9
10
11
12
import React, { useContext } from "react";
function ChildComponent() {
const user = useContext(MyContext); // 使用 useContext 獲取數據
return (
<div>
<p>名字: {user.name}</p>
<p>年齡: {user.age}</p>
</div>
);
}
使用 Context.Consumer
:
1
2
3
4
5
6
7
8
9
10
11
12
function ChildComponent() {
return (
<MyContext.Consumer>
{(user) => (
<div>
<p>名字: {user.name}</p>
<p>年齡: {user.age}</p>
</div>
)}
</MyContext.Consumer>
);
}
useContext
是使用 Context 的更簡潔方法,而 Consumer
提供了更多控制,但語法較為冗長。
3. Context 的實際應用場景
(1) 主題切換
Context 非常適合處理全局的 UI 主題狀態,如深色模式和淺色模式切換。
範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// themeContext.js
import React, { useState, createContext, useContext } from "react";
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}
在這裡,我們創建了一個 ThemeContext
並通過 ThemeProvider
將主題狀態和切換主題的邏輯傳遞給子組件。然後,任何組件都可以使用 useTheme
來訪問當前主題和切換主題的功能。
使用 Context 的組件:
1
2
3
4
5
6
7
8
9
10
11
12
import React from "react";
import { useTheme } from "./themeContext";
function ThemeToggleButton() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
切換到 {theme === "light" ? "暗黑模式" : "淺色模式"}
</button>
);
}
(2) 用戶認證狀態
Context 也非常適合處理用戶的認證狀態,這樣我們可以在整個應用中共享用戶信息。
範例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// authContext.js
import React, { useState, createContext, useContext } from "react";
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = (userData) => {
setUser(userData);
};
const logout = () => {
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
return useContext(AuthContext);
}
在這個範例中,我們創建了一個 AuthContext
來管理用戶的登入狀態,並在應用中提供 login
和 logout
功能。
使用 Context 的組件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from "react";
import { useAuth } from "./authContext";
function UserProfile() {
const { user, logout } = useAuth();
if (!user) {
return <p>請先登入</p>;
}
return (
<div>
<p>用戶名: {user.name}</p>
<button onClick={logout}>登出</button>
</div>
);
}
4. 多個 Context 的組合使用
有時我們可能需要在應用中使用多個 Context,例如主題和認證狀態。我們可以通過多層 Provider
包裹來實現:
1
2
3
4
5
6
7
8
9
10
function App() {
return (
<AuthProvider>
<ThemeProvider>
<UserProfile />
<ThemeToggleButton />
</ThemeProvider>
</AuthProvider>
);
}
這樣,UserProfile
和 ThemeToggleButton
組件既能訪問認證狀態,也能訪問主題狀態。
5. Context 的注意事項
- 性能問題:頻繁變化的 Context 值會導致每次重新渲染時所有使用該 Context 的子組件都重新渲染。對於高頻變化的數據,可以考慮將其移到更局部的狀態中。
- 避免過度使用:雖然 Context 是非常強大的工具,但在小規模數據共享時(如兩三層的
props
傳遞),過度使用 Context 可能會使代碼複雜化。
總結
React Context API 提供了一個有效的方式來處理組件之間的數據共享,尤其是當需要跨多層組件傳遞數據時,能夠避免繁瑣的 props
傳遞。通過正確使用 Context,我們可以輕鬆管理全局狀態,如用戶身份驗證、主題設置等,使應用更加靈活和可維護。