React Context 跨层传值

React Context 跨层传值

前置:React useRef 与 DOM

目标:会建 Provider + useContext;知道什么时候不该用 Context。

引言

props 适合父子:父把值传给直接孩子。

跨很多层时(顶栏主题开关 → 深层 Panel),层层 props 叫 prop drilling,又吵又脆。

Context 做「依赖注入」:上面 Provider 放一份值,任意深层用 useContext 取,中间组件不用接力。

本篇 demo:主题 light/dark,Toolbar 切换,Panel 直接读主题变色。

动手

完整代码:react2/11-context/demo

bash 复制代码
cd react2/11-context/demo
npm install && npm run dev

点「切换」,看工具栏文案和面板底色一起变。


1. 三步:create → Provider → useContext

tsx 复制代码
type Theme = 'light' | 'dark'
const ThemeCtx = createContext<{ theme: Theme; toggle: () => void } | null>(null)

function ThemeProvider({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState<Theme>('light')
  const toggle = () => setTheme((t) => (t === 'light' ? 'dark' : 'light'))
  return (
    <ThemeCtx.Provider value={{ theme, toggle }}>
      {children}
    </ThemeCtx.Provider>
  )
}

function useTheme() {
  const ctx = useContext(ThemeCtx)
  if (!ctx) throw new Error('useTheme 必须在 ThemeProvider 内')
  return ctx
}
步骤 干什么
createContext 建上下文;默认值常用 null,配合自定义 hook 做「必须在 Provider 内」检查
Provider value={...} 把当前值注入子树
useContext / useTheme 消费;封装 hook 可读性更好

2. 深层组件直接消费

tsx 复制代码
function Toolbar() {
  const { theme, toggle } = useTheme()
  return (
    <div className="row">
      <span>当前主题:{theme}</span>
      <button type="button" onClick={toggle}>切换</button>
    </div>
  )
}

function Panel() {
  const { theme } = useTheme()
  return (
    <section style={{ background: theme === 'dark' ? '#0f172a' : '#fff' }}>
      <p>深层组件也能读到 Context,不必层层 props。</p>
    </section>
  )
}

export default function App() {
  return (
    <ThemeProvider>
      <Toolbar />
      <Panel />
    </ThemeProvider>
  )
}

App 只包一层 Provider;中间没有「theme 透传」。


3. 适合 / 不适合

适合 不适合
主题、locale、当前用户 每个按键都变的表单字段
依赖注入式配置 只传一两层就能搞定的数据
低频、横切关注点 高频大树更新(易牵动整棵消费者)

高频客户端状态 → 拆多个 Context,或上 Zustand(15 篇)。

服务端列表 / 详情 → TanStack Query(07 篇),别硬塞 Context。


4. 常见坑

做法 问题
Provider 外用 useTheme 拿到 null / 抛错;检查挂载位置
value={{ theme, toggle }} 每次新建对象 所有消费者可能跟着重渲染;可 useMemo 稳住 value,或拆成「状态 Context + 派发 Context」
什么都塞一个大 Context 一处改、全家刷;按域拆分
用 Context 代替近距离 props 过度设计,可读性变差

demo 在练什么

  1. createContext + Provider + 自定义 useTheme
  2. 跨组件读写主题,无 props 钻取
  3. 建立「低频横切用 Context」的选型直觉

自己改一改:再加一个 LocaleContext;或把 value 用 useMemo 包起来观察渲染。


下一篇

React useReducer 复杂状态

相关推荐
JudithHuang1 小时前
React 列表与表单
react.js
JudithHuang1 小时前
React useRef 与 DOM
react.js
JudithHuang1 小时前
React useReducer 复杂状态
react.js
JudithHuang1 小时前
React 组件与 Props
react.js
JudithHuang1 小时前
React:第一个 Vite 应用
react.js
JudithHuang1 小时前
React State 与事件
react.js
JudithHuang1 小时前
React 大型项目目录骨架
react.js