useContext
useContext
是 React 提供的其中一個 Hook,用來讀取 Context 的資料。
在 React 中,資料通常需要透過 props 一層層傳遞(例如:App → Navbar → Button),但如果元件巢狀層級很深,就會變得麻煩。
這時候就可以用Context,建立「全域狀態」,讓不同元件間共享;而 useContext
則是能讓元件能快速讀取 Context 中的工具。
當「某個狀態需要在很多元件共享」時,就適合用 Context + useContext
常見的例子:
MyContext.js
import { createContext } from "react";
const MyContext = createContext();
export default MyContext;
createContext()
:建立 Context 容器MyContext
:共享資料的入口MyProvider.js
import MyContext from "./MyContext";
import { useState } from "react";
function MyProvider({ children }) {
const [value, setValue] = useState("(…)");
return (
<MyContext.Provider value={{ value, setValue }}>
{children}
</MyContext.Provider>
);
}
export default MyProvider;
MyProvider
:包住其他元件,負責提供資料<MyContext.Provider value={{value, setValue}}>
:共享 value
和 setValue
給子元件使用註:children 是一個prop屬性,代表「被元件標籤包住的內容」
useContext
取得資料Child.js
import { useContext } from "react";
import MyContext from "./MyContext";
function Child() {
const { value, setValue } = useContext(MyContext);
return (
<div>
<p>{value}</p>
<button onClick={() => setValue("New Value")}>
更新資料
</button>
</div>
);
}
useContext(MyContext)
:取出 Provider 提供的 value
和 setValue
<button onClick={() => setValue("New Value")}>
:點擊按鈕後會更新 value
→ 畫面自動重新渲染App.js
import MyProvider from "./MyProvider";
import Child from "./Child";
function App() {
return (
<MyProvider>
<Child />
</MyProvider>
);
}
<MyProvider>
包住整個應用程式,這樣 Child(或其他子元件)都能存取 value
import { createContext, useState } from "react";
const ThemeContext = createContext();
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 { ThemeProvider, ThemeContext };
ThemeContext
:建立 Context,負責共享主題資料ThemeProvider
:管理 theme
狀態,並提供 toggleTheme
切換主題value={{ theme, toggleTheme }}
:讓 theme 和 toggleTheme 可以提供給子元件取用import Navbar from "./Navbar";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { ThemeProvider, ThemeContext } from "./ThemeContext";
import { useContext } from "react";
function App(){
return (
<ThemeProvider>
<Router>
<MainApp/>
</Router>
</ThemeProvider>
);
}
function MainApp(){
const { theme } = useContext(ThemeContext);
return (
<div className={`App ${theme}`}>
<Navbar />
<div className="content">
<Routes>
(...)
</Routes>
</div>
</div>
);
}
export default App;
<ThemeProvider>
:包住整個 App,讓所有子元件能共享主題狀態useContext(ThemeContext)
:在 MainApp
取得目前 theme
,並根據主題切換 className
import { useContext } from "react";
import { Link } from "react-router-dom";
import { ThemeContext } from "./ThemeContext";
const Navbar = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<nav className={`navbar ${theme}`}>
<h1>The Blog</h1>
<div className="links">
(…)
<button onClick={toggleTheme} className="theme-btn">
{theme === "light" ? "Dark" : "Light"}
</button>
</div>
</nav>
);
};
export default Navbar;\
useContext(ThemeContext)
:取得 theme
和 toggleTheme
<button onClick={toggleTheme} className="theme-btn">
:點擊按鈕後可以切換主題.App.light (…)
.App.dark (…)
theme
加上的 className
(light
或 dark
),應用不同樣式,達到切換樣式的效果ThemeContext
和 ThemeProvider
→ 管理狀態<ThemeProvider>
包住應用程式 → 所有子元件都能存取主題useContext
→ 讀取 theme
,並用按鈕切換主題.light
和 .dark
→ 顯示不同樣式瀏覽器執行畫面