全局状态

收藏夹要在文章卡片和顶栏"我的收藏"之间同步,主题色要全局生效——这类被许多组件共享的状态,用 props 一层层传递(prop drilling)既啰嗦又易错。React 提供了 Context 来做跨层共享,用 useReducer 集中管理更新逻辑。本章给博客加上一个全局的深色模式。

prop drilling 的痛点

props 只能父子相传:theme 要从 App 传给 Header 再传给 Button,中间那层 Header 根本用不到也得跟着传。层级一深,代码里全是透传,改个名字要动许多文件。

createContext 与 Provider

先创建 Context 对象(可给默认值),再用 .Provider 包裹需要共享数据的整棵子树:

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

export const ThemeContext = createContext("light"); // 默认浅色
// App.jsx
const [theme, setTheme] = useState("light");

<ThemeContext.Provider value={theme}>
  <Header />
  <ArticleList posts={posts} />
</ThemeContext.Provider>

useContext 读取

Provider 内部的任意组件(哪怕隔着很多层)都能用 useContext 直接取值,无需逐层传 props:

// Header.jsx
import { useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";

export default function Header() {
  const theme = useContext(ThemeContext); // 读到 "light" 或 "dark"
  return <header className={`header ${theme}`}>我的博客</header>;
}

useReducer 集中更新

全局状态通常有多个动作(切换、重置……)。useReducer 把"旧状态 + 动作 → 新状态"的规则收进一个纯函数 reducer:

function themeReducer(state, action) {
  switch (action.type) {
    case "toggle":
      return state === "light" ? "dark" : "light";
    case "reset":
      return "light";
    default:
      return state;
  }
}

const [theme, dispatch] = useReducer(themeReducer, "light");
dispatch({ type: "toggle" }); // 触发一次切换

更新逻辑集中在一处,组件里只需要 dispatch,不再散落各种 setState。

Context + Reducer 组合

两者合体就是一套轻量级全局状态管理:Context 负责"跨层读取",useReducer 负责"集中更新"。把 state 和 dispatch 一起放进 Provider,需要改数据的组件取 dispatch,只读的组件取 state:

<ThemeContext.Provider value={{ theme, dispatch }}>
  <Header />       {/* Header 读 theme 换样式 */}
  <ThemeSwitch />  {/* ThemeSwitch 调 dispatch 切换 */}
</ThemeContext.Provider>

小结

Context 解决"跨层传值",useReducer 解决"更新逻辑分散",适合主题、登录用户、收藏这类全局数据。项目继续变大时,可在这一套思路上引入 Redux 等更成熟的方案。

笔记加载中…