CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
React 核心/课时/Context 共享状态
RawBlame
课时目录14 节

React 核心

  1. 01React 是什么
  2. 02JSX 与渲染
  3. 03函数组件
  4. 04Props 与 State
  5. 05事件处理
  6. 06条件渲染与列表
  7. 07useEffect
  8. 08useRef 与 DOM
  9. 09useMemo、useCallback 与自定义 Hook
  10. 10表单与受控组件
  11. 11Context 共享状态
  12. 12React Router 入门
  13. 13数据获取与错误边界
  14. 14综合练习与 Next.js 方向

Context 共享状态

createContext、Provider、跨层传值。

30 分钟

Context 共享状态

这一课你将能做到

  1. 说出 Context 解决「props 一层层往下传」的麻烦
  2. 看懂 Provider + useContext 的基本结构
  3. 知道不要把所有数据都塞进 Context

为什么要学

主题色、当前用户、走法偏好——很多组件都要读。
若用 props 层层传递(prop drilling),中间层只为「转发」而存在,又烦又脆:Header 并不关心 user 怎么来的,却必须写 user={user} 往下递。

Context 提供「在树上的某处放一份值,深处直接读」。
人话:广播站。上面架天线(Provider),下面收音机(useContext)。

本站 AuthProvider 就是这类模式:登录态不必穿过每一层布局。

先建立图像

<AuthProvider>          ← 提供 { user, setUser }
  <Page>
    <Header />          ← useContext 读取 user
    <Main />            ← 不需要 user 的层不用接 props
  </Page>
</AuthProvider>

没有 Provider 就调用 useContext,会拿到 createContext 时的默认值(常为 null),于是你要自己报错提醒。

跟着做

步骤 1:最小 Context(完整可抄)

import { createContext, useContext, useMemo, useState } from "react";

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const value = useMemo(() => ({ user, setUser }), [user]);
  return (
    <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth 必须在 AuthProvider 内");
  return ctx;
}

export function WhoAmI() {
  const { user } = useAuth();
  return <span>{user ? user.name : "未登录"}</span>;
}

export function LoginButton() {
  const { setUser } = useAuth();
  return (
    <button type="button" onClick={() => setUser({ name: "ada" })}>
      演示登录
    </button>
  );
}

useMemo 避免每次渲染都新建 value 对象,导致所有消费者无谓更新。入门先知道「对象当 value 要小心」。

步骤 2:在树顶包起来

export function App() {
  return (
    <AuthProvider>
      <WhoAmI />
      <LoginButton />
    </AuthProvider>
  );
}

WhoAmI 不必从 App 接 user props。

步骤 3:先提升,不够再 Context

两个兄弟要同一份勾选:父组件 state 往往更简单,别一上来 Context。
跨很多层、很多页都要读的「当前用户 / 主题」再 Context。

步骤 4:拆分「值」与「dispatch」

高频更新的 value 与稳定的 setter 可分两个 Context,减少无关重渲染。入门先做一个 Provider 也行,知道有这招。

讲清楚要点

  1. 先状态提升,不够再 Context。
  2. Context 适合变化不疯狂的全局信息(主题、用户)。列表滚动位置、每秒心跳不要塞进去,会逼整片树重渲染。
  3. 按领域拆(Auth、Theme),避免一个上帝 Context。
  4. 自定义 useAuth:把「必须在 Provider 内」的检查收口,调用处干净。
  5. 本站读真实 AuthProvider 对照,比再抄一套教程有用。

你可能会懵的地方

  • Context 是不是 Redux?
    不是。Redux 等是更重的方案(时间旅行、中间件)。很多应用 Context + hooks 就够。不要为简历先上 Redux。

  • 必须拆很多 Context 吗?
    按变化频率和领域拆更好。主题很少变、聊天消息狂变,别捆在一个 value。

  • value 写成 value={{ user, setUser }} 行不行?
    能跑。但每次 Provider 渲染都是新对象。用 useMemo 更稳。

  • 深层组件改了 Context,中间层会重渲染吗?
    消费了该 Context 的会。没消费的不一定。仍不要把高频数据放进去。

  • Context 替代所有状态库?
    简单共享可以;复杂高频更新要考虑拆分或专用库。

错法对照

错法问题正解
列表滚动位置进 Context狂渲染本地 state
无 Provider 就 useContext默认 null、白屏树外包 Provider
所有 API 数据进一个 store难维护按页取数 + 少量全局
用 Context 代替 props 传标题过度设计父传子即可
Provider 包太低子树读不到包在真正需要的祖先
value 每次渲染新对象且未 memo下游全刷稳定 value 或拆分

自测三问

  1. Context 主要减轻什么痛苦?什么时候用提升就够?
  2. 什么样的数据适合放 Context?举一个不适合的。
  3. 为何 Provider 的 value 常用 useMemo?

小结一句话

Context 向深处广播少量全局状态;先提升,再广播,别当垃圾桶。

动手加深

主题色 Context:Provider 给按钮,深层文本读取;确认不必层层 props。

跟着做(加厚 · react-context)

步骤:最小可运行对照

在 Vite 或 Next 练习页粘贴本课核心示例,改一个输入,确认屏幕变化符合预期。再故意写一个错法表里的写法,看控制台/界面如何坏,然后改回。

每个概念都问:state 在谁手里?UI 哪一块会因它重绘?

操作顺序:打开对应文件 → 改一处可观察点(文案、类型、className 或分支)→ 保存看结果 → 复原或留下有意义的小改动。

步骤:错法故意练一次

先按「用 jQuery 式直接改 DOM 冒充完成」做 30 秒(或在注释里写出若这样做会怎样),再改成「改数据(state/props)让 UI 推导出来」。 目的不是留坑,而是让失败现象进长期记忆。

你可能会懵的地方(加厚)

  • 热更新后状态丢了?
    正常:整树重挂会重置 state。用 key 或外提状态保留;开发期别被吓到。

  • 和文档示例不一致?
    以你锁的 React 大版本 + react.dev 为准;旧博客的 class 组件示例仅作历史阅读。

  • 这课和前后课怎么接?
    回看大纲上一课的小结一句、下一课标题;用自己的话写「本课产出什么可观察结果」。写不出来就重做跟着做。

错法对照(加厚)

错法问题正解
用 jQuery 式直接改 DOM 冒充完成假完成/埋雷改数据(state/props)让 UI 推导出来
只看不敲第二天全忘至少跑通本课步骤
跳过自测三问以为会了闭卷答再对稿

延伸

  • Passing Data Deeply with Context
  • 下一课:路由入门(URL 与页面)。
加载本节练习…
← 上一课表单与受控组件下一课 →React Router 入门