全局状态
收藏夹要在文章卡片和顶栏"我的收藏"之间同步,主题色要全局生效——这类被许多组件共享的状态,用 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 等更成熟的方案。