首页 / React 19 入门教程 / Context 跨层级传递

React 19 入门教程

Context 跨层级传递

本教程共 50 篇 · 第 23 篇 · 更新于 2026-07-29 · 约 7 分钟阅读

ReactContextcreateContextuseContextProvider

23. Context 跨层级传递

本节目标:理解 prop drilling 问题,掌握 Context 三件套,能跨多层组件传递数据。

prop drilling 是什么

状态提升解决了兄弟组件共享数据。但如果组件层级很深,数据要经过层层传递:

Page → Layout → Sidebar → Nav → UserAvatar

Page 持有 user 数据,UserAvatar 需要它。中间三个组件只是”搬运工”,被迫接收和传递它们不关心的 props。这就是 prop drilling(prop 逐级透传)。

function Page({ user }) {
  return <Layout user={user} />;
}

function Layout({ user }) {
  return <Sidebar user={user} />;
}

function Sidebar({ user }) {
  return <Nav user={user} />;
}

function Nav({ user }) {
  return <UserAvatar user={user} />;
}

每一层都要写 user={user},又丑又难维护。

Context 的解决方案

Context 像一条”隐形管道”,跳过中间层直达目标:

Page(提供数据)
├── Layout(不用管)
│   ├── Sidebar(不用管)
│   │   ├── Nav(不用管)
│   │   │   └── UserAvatar(直接读取)

三步使用 Context

第一步:创建 Context

// UserContext.js
import { createContext } from 'react';

export const UserContext = createContext(null);

createContext 的参数是默认值。没有匹配到 Provider 时,useContext 返回这个值。

第二步:提供 Context

在需要共享数据的父组件,用 Provider 包裹:

import { UserContext } from './UserContext';

function Page() {
  const [user, setUser] = useState({ name: '张三', avatar: '🐱' });

  return (
    <UserContext value={user}>
      <Layout />
    </UserContext>
  );
}

Provider 的 value

value 可以是任何类型:对象、数组、函数、甚至另一个 state。

第三步:消费 Context

在任意后代组件里用 useContext 读取:

import { useContext } from 'react';
import { UserContext } from './UserContext';

function UserAvatar() {
  const user = useContext(UserContext);
  return <span>{user.avatar} {user.name}</span>;
}

Layout、Sidebar、Nav 都不用碰 user prop 了。

提供动态数据

Context 的 value 通常是 state,变化时所有消费者自动更新:

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext value={{ theme, setTheme }}>
      {children}
    </ThemeContext>
  );
}

子组件既能读也能改:

function ThemeToggle() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      当前:{theme}
    </button>
  );
}

多个 Context 嵌套

一个组件可以消费多个 Context:

function Header() {
  const user = useContext(UserContext);
  const { theme } = useContext(ThemeContext);
  const { locale } = useContext(LocaleContext);

  return <header className={theme}>...</header>;
}

Provider 也可以任意嵌套:

<UserContext value={user}>
  <ThemeContext value={theme}>
    <LocaleContext value={locale}>
      <App />
    </LocaleContext>
  </ThemeContext>
</UserContext>

Context 不是万能的

Context 有它的适用场景,不是什么东西都往里塞:

  • 当前用户信息
  • 主题/语言设置
  • 认证状态

不适合频繁变化的数据(每次变化都重新渲染所有消费者),也不适合替代所有 props。

不要滥用 Context

如果数据只在父子两层之间传递,用 props 就行。Context 是为”跨很多层”设计的。

本节要点

  • prop drilling:数据经过不相关的中间层传递
  • Context 三件套:createContext → Provider → useContext
  • Provider 的 value 通常是 state
  • 适合跨多层的”全局”数据,不适合替代所有 props