Skip to main content

useContext

7. useContext

📌 用途

跨元件傳遞資料,避免一層一層往下傳 props(prop drilling)。

📌 適合場景

  • 使用者登入資訊
  • 主題切換(dark / light)
  • 全域語系設定

📌 完整使用流程

useContext 需要搭配 三個步驟 才能正確運作:

1. createContext() → 建立 Context 物件
2. <Context.Provider> → 在最外層包住所有需要使用的元件
3. useContext() → 在子元件中讀取資料

📌 Step 1 |建立 Context(獨立檔案)

建議將 Context 抽出為獨立檔案,方便多處引用:

// src/context/ThemeContext.jsx
import { createContext, useState } from "react";

export const ThemeContext = createContext(null);

export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");

return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
info

🔍 children 是什麼?

children 是 React 的內建 props,代表被包在元件標籤內部的所有子內容

當你在 App.jsx 這樣寫:

<ThemeProvider>
<BrowserRouter>
<Routes>...</Routes>
</BrowserRouter>
</ThemeProvider>

<BrowserRouter> 以及它底下的所有路由,就會成為 ThemeProviderchildren,被放進 <ThemeContext.Provider> 裡面渲染。

這樣的結果是:所有被 ThemeProvider 包住的元件,不論在路由的第幾層,都能透過 useContext(ThemeContext) 拿到資料

ThemeProvider
└── {children} ← BrowserRouter 及底下所有路由都在這裡
└── Routes
├── Home → useContext 可用 ✅
├── About → useContext 可用 ✅
└── Profile → useContext 可用 ✅

📌 Step 2 |在 App.jsx 最外層包上 Provider

⚠️ 重點:Provider 必須包在所有要使用這個 Context 的元件外層,路由底下的所有頁面才能正常取用。

// src/App.jsx
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { ThemeProvider } from "./context/ThemeContext";
import Home from "./pages/Home";
import About from "./pages/About";

function App() {
return (
<ThemeProvider>
{" "}
{/* ← Provider 包在路由最外層 */}
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
</ThemeProvider>
);
}

export default App;

📌 Step 3 |在任意子元件中使用 useContext

不管元件在路由的哪一層,都可以直接呼叫 useContext 取得資料,不需要逐層傳 props:

// src/pages/Home.jsx
import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";

function Home() {
const { theme, setTheme } = useContext(ThemeContext);

return (
<div>
<p>目前主題:{theme}</p>
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
切換主題
</button>
</div>
);
}

export default Home;

📌 Provider 位置示意

App.jsx
└── ThemeProvider ← Context 在這裡提供資料
└── BrowserRouter
└── Routes
├── Home ← 可以用 useContext ✅
├── About ← 可以用 useContext ✅
└── Profile ← 可以用 useContext ✅