React 组件通信到底怎么写:四种常用方式一次讲清

编程狮(w3cschool.cn) 2026-09-04 17:05:13 浏览数 (47)
反馈

React 里组件越拆越多,数据该怎么在它们之间流动,是新手最容易懵的地方。很多初学者一上来就写满整个页面,等到要拆组件、传数据时彻底卡住。组件通信其实就四种常用方式:父传子用 props、子传父用回调、兄弟之间做状态提升、跨层级用 Context。本文给每种方式配一个最小可运行示例,并说明它什么时候该上。下面每种方式都从“它解决什么”讲起,对照着抄就能用。你照着示例改两遍,就能根据场景选对写法,不再东抄一段西抄一段。

React 组件通信四种常用方式封面图

一、父传子:用 props 把数据“递下去”

把组件想象成工厂的工序,父组件是上一道工序,子组件是下一道。父组件想把自己手里的数据交给子组件,就通过“属性”传过去,子组件在参数里接收,这个参数在 React 里叫 props

function Child(props) {
  return <p>你好,{props.name}</p>;
}


function Parent() {
  const w3cschoolName = '编程狮';
  return <Child name={w3cschoolName} />;
}

上面 Parentw3cschoolName 通过 name 属性传给 ChildChildprops.name 取到并显示。注意 props 在子组件里是只读的,子组件不能直接改它,只能“用”,不能“改”——这是 React 的单向数据流设计,也是它好维护的原因。

当你要系统理解组件与 JSX 的写法,可以先过一遍 React 教程,把函数组件、props 和事件这套主线理顺,后面几种通信方式都是在这之上做变化。

💡 小提示:props 名字随便起,但尽量见名知意,别用 ab 这种含糊名字,组件一多你就分不清谁是谁了。

二、子传父:用回调函数“传回来”

父传子解决“往下给”,那子组件想告诉父组件一件事(比如按钮被点了、输入框变了),怎么办?React 不允许子组件直接改父组件的状态,正确做法和现实里“你按门铃通知屋里人”一样:父组件先把一个回调函数通过 props 传下去,子组件在合适的时机调用它,把数据带回来。

import { useState } from 'react';


function Child({ onGreet }) {
  return <button onClick={() => onGreet('编程狮')}>点击打招呼</button>;
}


function Parent() {
  const [msg, setMsg] = useState('');
  return (
    <div>
      <Child onGreet={(value) => setMsg(value)} />
      <p>收到:{msg}</p>
    </div>
  );
}

这里 ParentonGreet 这个函数交给 ChildChild 点击时调用 onGreet('编程狮'),父组件的 setMsg 就被触发,状态更新、视图刷新。核心就一句:子传父,不是子改父,而是子“叫父自己改”。

组件里的状态与函数写法,底层都依赖 JavaScript 教程 里的箭头函数与解构赋值基础,把这两块吃透,回调这种写法会变得非常自然。

三、兄弟组件:把状态“提升”到共同父级

如果两个兄弟组件都要用同一份数据,谁也不该单独藏着——正确的做法是把这份数据提到它们共同的父组件里,再由父组件分别用 props 分发给两个孩子。这叫“状态提升”。

import { useState } from 'react';


function Input({ value, onChange }) {
  return <input value={value} onChange={(e) => onChange(e.target.value)} />;
}
function Show({ value }) {
  return <p>你输入了:{value}</p>;
}
function Parent() {
  const [text, setText] = useState('');
  return (
    <>
      <Input value={text} onChange={setText} />
      <Show value={text} />
    </>
  );
}

Input 负责改、Show 负责显示,但它们俩本身都不存数据,真正的数据 textParent 手里。任何一方的变化都回流到父组件,再由父组件统一下发,兄弟之间就通过“共同的父亲”完成了通信。

⚠️ 注意:别试图让两个兄弟组件互相直接调用方法,React 没有这种官方通道。一律提升到父级,结构才清晰、才好调试。

四、跨层级:用 Context 避开“透传地狱”

前三种都靠 props 一层层传。可如果组件嵌套了五六层,最底下的组件要用最顶层的数据,就得每层都写一遍 props,又臭又长,这叫“透传地狱”。Context 就是为此而生的:它在组件树里开一条“专用通道”,顶层放数据,任何深层子孙直接取,中间层完全不掺和。

import { createContext, useContext } from 'react';


const UserContext = createContext();


function App() {
  return (
    <UserContext.Provider value="编程狮">
      <DeepChild />
    </UserContext.Provider>
  );
}
function DeepChild() {
  const name = useContext(UserContext);
  return <p>深层组件拿到:{name}</p>;
}

AppProvidervalue 放进去,DeepChild 哪怕隔了十层,也能用 useContext 直接拿到,中间组件一个 props 都不用写。记不住 useContextuseState 这些 hooks 的写法时,JavaScript 速查手册 能按名快速查到用法,写代码时旁边开一份很省心。

💡 小提示:Context 适合“全局、变化不频繁”的数据,比如主题、登录用户。如果数据更新很频繁,别全塞进一个 Context,否则一变全树重渲染,性能会吃亏。

五、四种方式怎么选:一张对照表

讲完四种,关键还是“什么时候用哪个”。记住一个原则:能就近就别绕远。父子相邻用 props 最直接;子要回传用回调;兄弟共用就提升状态;跨很多层才上 Context。下面这张表帮你快速对号入座:

场景 推荐方式 一句话理由
父给子数据 props 最直接,单向下传
子通知父 回调函数 子不擅改父,只负责呼叫
兄弟共用数据 状态提升 提到共同父级统一分发
跨多层取数据 Context 避免一层层透传

实际项目里往往是组合使用:父传子用 props,子传父用回调,多个兄弟共享就提升,全局配置再交给 Context。没有“最好”的方式,只有“最合适当前距离”的方式。

举一个真实组合:顶部导航要显示当前用户名,这是跨层数据,用 Context 存 user 最省事;导航里的搜索框输入要实时过滤下方列表,这是父子关系,用 props 加回调即可;列表和分页是两个兄弟,共享 page 状态,就提升到它们的共同父级。你看,四种方式在同一页面里各司其职,并不冲突。先想清楚“这段数据要在哪些组件之间流动”,再选最短的那条路,通信就不再是难题。

React 组件通信四种方式怎么选

总结

React 组件通信的四种方式,本质都是在回答“数据往哪走”:父传子走 props,子传父走回调,兄弟共享走状态提升,跨层级走 Context。单向数据流是底色——数据只能从父往子流,子想影响父,就通过回调让父自己改。

你该带走的要点:第一,props 只读,子组件别试图直接改;第二,状态尽量放在“用得到它的最低共同父级”;第三,Context 留给真正跨层的全局数据。把这些记熟,组件之间的数据流向就不会再乱。下一步建议顺着 React 教程把 hooks 与组合模式练扎实,基础就真正稳了。

延伸学习

想把这块知识系统补齐,可以按这个顺序来:

  1. 先跟着 AI 设计网页实战课程 用 React 组件搭一个真实页面,实战课程把通信写法融入项目,边做边理解最牢;
  2. 想看更多“翻车现场”,读 React 渲染黑洞笔记,它把无限渲染黑洞、远程木马、HOC 套娃等反例都拆明白了;
  3. 在框架之间摇摆时,参考 前端三大框架对比,这篇讲清 React、Angular、Vue.js 的取舍,帮你少走选型弯路。

常见问题

Q:props 和 state 到底有什么区别?

A:props 是父组件传下来的“只读快递”,子组件只能看不能用改;state 是组件自己管的“可变内存”,用 useState 声明、自己改。一个对外只读,一个对内可变。

Q:子组件能直接改父组件的 state 吗?

A:不能直接改。正确姿势是父组件传一个回调函数下去,子组件调用它,由父组件在自己的函数里改 state,这叫“子传父用回调”。

Q:状态提升会不会让父组件变得很臃肿?

A:会有一点,但这是 React 推荐的清晰结构。如果父组件因此过大,可以把相关逻辑抽成自定义 hook,或用 Context 分担,别为了“瘦父组件”而破坏单向数据流。

Q:Context 是不是可以替代所有 props 透传?

A:不建议。Context 适合变化不频繁的全局数据,用太多会让组件耦合变强、重渲染范围变大。就近能传 props 的,就别上 Context。

0 人点赞