iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
Modern Web

30天入門:學會第一個前端框架-React系列 第 27

Day 27 | React入門:useContext-共享全域狀態

  • 分享至 

  • xImage
  •  

什麼是 useContext

useContext 是 React 提供的其中一個 Hook,用來讀取 Context 的資料。
在 React 中,資料通常需要透過 props 一層層傳遞(例如:App → Navbar → Button),但如果元件巢狀層級很深,就會變得麻煩。
這時候就可以用Context,建立「全域狀態」,讓不同元件間共享;而 useContext 則是能讓元件能快速讀取 Context 中的工具。


什麼時候會需要用到useContext

當「某個狀態需要在很多元件共享」時,就適合用 Context + useContext
常見的例子:

  1. 深色/淺色模式切換
    • 主題樣式要影響整個 App 時,需要 Context 共享
  2. 使用者登入狀態
    • 例如 user 資料要在 Navbar、Profile、Dashboard 都能存取
  3. 語言切換
    • 例如中英文切換,要讓所有網站中,所有文字元件都能同步更新
  4. 購物車資料
    • 購物網站的「購物車內容」要在不同頁面共用

useContext的用法

1. 建立 Context

MyContext.js

import { createContext } from "react";

const MyContext = createContext();
export default MyContext;
  • createContext():建立 Context 容器
  • MyContext:共享資料的入口

2. 建立 Provider

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}}>:共享 valuesetValue 給子元件使用

註:children 是一個prop屬性,代表「被元件標籤包住的內容」

3. 在元件中使用 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 提供的 valuesetValue
  • <button onClick={() => setValue("New Value")}>:點擊按鈕後會更新 value → 畫面自動重新渲染

4. 包住 Provider,讓所有子元件都能共享 Context

App.js

import MyProvider from "./MyProvider";
import Child from "./Child";

function App() {
  return (
    <MyProvider>
      <Child />
    </MyProvider>
  );
}
  • <MyProvider> 包住整個應用程式,這樣 Child(或其他子元件)都能存取 value

總結:

  • Context:建立一個「共享資料」的容器。
  • Provider:提供資料。
  • useContext:取用資料。

範例:深色/淺色模式切換

1. 建立 ThemeContent.js

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 可以提供給子元件取用

2. 在 App.js 使用 ThemeProvider

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

3. 在 Navbar.js 切換主題

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) :取得 themetoggleTheme
  • <button onClick={toggleTheme} className="theme-btn">:點擊按鈕後可以切換主題

4. CSS設定

.App.light (…)
.App.dark (…)
  • 根據 theme 加上的 className (lightdark),應用不同樣式,達到切換樣式的效果

總結

  1. 建立 ThemeContextThemeProvider → 管理狀態
  2. 在 App.js 用 <ThemeProvider> 包住應用程式 → 所有子元件都能存取主題
  3. 在 Navbar.js 使用 useContext → 讀取 theme,並用按鈕切換主題
  4. 用 CSS 設定 .light.dark → 顯示不同樣式

瀏覽器執行畫面
https://i.meee.com.tw/UwlVHm9.gif


上一篇
Day 26 | React入門:404 NotFound 頁面處理
下一篇
Day 28 | React入門:React Router v6 新舊版本前後差異
系列文
30天入門:學會第一個前端框架-React29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言