5种常用 组件通信 方式你真的都会了吗

229 阅读6分钟

在用 React 开发项目时,组件之间的“聊天”绝对是个绕不开的话题。小项目还好,父子传个 props 就完事儿了,但项目一大,组件一多,兄弟、跨层级、全局通信啥的,分分钟让人头大!今天就用最接地气的方式,带你一次性搞懂 5 种常见的组件通信方式😎


1. 父子组件通信——最基础的“你说我听”

原理:父组件通过 props 给子组件传递数据,子组件通过 props 接收。

详细说明:

父子通信是 React 里最常见、最基础的通信方式。父组件可以把任何数据(字符串、数字、对象、函数等)通过 props 传递给子组件。子组件只需要通过 props 对象接收即可。数据流是单向的,从父到子,子组件不能直接修改 props,只能读取。

例子:

// 父组件
function Parent() {
  const user = { name: "小明", age: 18 };
  return <Child name={user.name} age={user.age} />;
}

// 子组件
function Child(props) {
  return (
    <div>
      <p>我是{props.name}</p>
      <p>年龄:{props.age}</p>
    </div>
  );
}

场景举例:

  • 页面展示数据(如用户信息、商品列表等)
  • 父组件控制子组件的显示/隐藏、样式等

小结

  • 父传子,props 走起,简单直接。
  • 适合数据单向流动的场景,比如页面展示、表单输入等。
  • 子组件不能直接修改 props,保证了数据流的可控性。

2. 子传父通信——“我有话要说”

原理:父组件定义一个函数,通过 props 传给子组件,子组件调用这个函数,把数据“递”回去。

详细说明:

有时候,子组件需要把自己的状态或事件通知给父组件,比如表单提交、按钮点击等。这时,父组件可以把一个回调函数通过 props 传给子组件,子组件在合适的时候调用这个函数,并把数据作为参数传递回去。

例子:

// 父组件
function Parent() {
  const handleMsg = (msg) => {
    alert('子组件说:' + msg);
  };
  return <Child onMsg={handleMsg} />;
}

// 子组件
function Child(props) {
  return (
    <button onClick={() => props.onMsg('你好,爸爸!')}>
      点我给爸爸发消息
    </button>
  );
}

场景举例:

  • 表单提交(子组件收集数据,父组件处理)
  • 子组件触发父组件的某些操作(如弹窗、切换页面等)

小结

  • 父给子传函数,子调用函数传数据。
  • 适合表单提交、事件回调等场景,比如子组件要通知父组件“我点了按钮啦”。
  • 这种方式让父组件可以灵活控制子组件的行为。

3. 兄弟组件通信——“中间人”来帮忙

原理:兄弟组件不能直接通信,通常通过“共同的父组件”来中转。

详细说明:

在实际开发中,兄弟组件之间经常需要通信,比如左侧菜单点击后,右侧内容区要跟着变化。由于 React 的数据流是单向的,兄弟组件之间不能直接传递数据。最常见的做法是:把需要共享的数据提升到它们的共同父组件,由父组件负责管理状态,并通过 props 分别传递给兄弟组件。

例子:

function Parent() {
  const [msg, setMsg] = React.useState('');
  return (
    <div>
      <BrotherA onSend={setMsg} />
      <BrotherB msg={msg} />
    </div>
  );
}

function BrotherA({ onSend }) {
  return (
    <button onClick={() => onSend('A发来的消息')}>
      发送给B
    </button>
  );
}

function BrotherB({ msg }) {
  return <div>收到消息:{msg}</div>;
}

场景举例:

  • 左右面板联动(如菜单和内容区)
  • 多个表单项之间的联动校验

小结

  • 兄弟通信靠父组件“中转”。
  • 适合兄弟间偶尔需要互动的场景,比如列表和详情、左右面板等。
  • 状态提升是 React 推荐的做法,能让数据流更清晰。

4. 跨层级通信——Context 出马

原理:用 React 的 Context,可以让“爷爷”直接把数据传给“孙子”,不用一层层 props 传递。

详细说明:

当组件层级很深,需要把数据从顶层组件传到很深的子孙组件时,props 一层层传递会非常繁琐。这时可以用 Context,把数据“广播”到整个组件树,任何后代组件都能随时取用。

例子:

import React, { createContext, useContext } from 'react';

const MyContext = createContext();

function Grandpa() {
  return (
    <MyContext.Provider value="爷爷的秘密">
      <Parent />
    </MyContext.Provider>
  );
}

function Parent() {
  return <Child />;
}

function Child() {
  const secret = useContext(MyContext);
  return <div>孙子拿到了:{secret}</div>;
}

场景举例:

  • 主题切换(如暗黑/明亮模式)
  • 用户登录信息、权限控制
  • 多语言国际化

小结

  • Context 适合“全家共享”的数据,比如主题、用户信息等。
  • 用法简单,注意别滥用,容易让数据流变得混乱。
  • 适合多层嵌套、跨层级传递数据的场景。
  • Context 让全局数据管理变得更优雅,但不适合频繁变动的数据。

5. 任意组件通信——Redux 全局状态管理

原理:Redux 就像一个“全局快递站”,所有组件都能随时取件、寄件,数据集中管理,谁都能用。

详细说明:

Redux 是 React 生态中最流行的全局状态管理库。它把所有组件需要共享的数据集中到一个“仓库”里,任何组件都可以随时读取和修改。Redux 适合大型项目、多人协作、数据流动复杂的场景。

基本流程

  1. 用 @reduxjs/toolkit 创建仓库(store);
  2. 用 react-redux 连接仓库和组件;
  3. 组件用 useSelector 取数据,用 useDispatch 派发动作(修改数据)。

例子:

// store.js
import { configureStore, createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    add: (state) => { state.value += 1; }
  }
});

export const { add } = counterSlice.actions;
export default configureStore({ reducer: { counter: counterSlice.reducer } });

// App.jsx
import { Provider, useSelector, useDispatch } from 'react-redux';
import store, { add } from './store';

function Counter() {
  const count = useSelector(state => state.counter.value);
  const dispatch = useDispatch();
  return (
    <div>
      <span>计数:{count}</span>
      <button onClick={() => dispatch(add())}>加1</button>
    </div>
  );
}

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

场景举例:

  • 用户登录状态、购物车、全局消息通知
  • 多人协作、复杂业务逻辑
  • 需要持久化、异步操作的数据

小结

  • Redux 适合大型项目、数据需要全局共享的场景。
  • 配合 react-redux,组件随时随地都能“收发快递”📦。
  • 适合复杂业务、多人协作、数据流动频繁的项目。
  • Redux 让状态管理更规范,但初学者需要适应一下它的“套路”。

总结与复习表

其实组件通信没你想的那么难,选对方式,写起来就很顺手!下面这张表,帮你一秒回忆所有通信方式和适用场景:

通信方式适用场景关键点/用法
父子通信父传子/子传父props 传递/回调函数
兄弟通信兄弟组件父组件中转
跨层级通信多层嵌套Context + useContext
任意组件通信全局/复杂项目Redux + useSelector/useDispatch

结语:

  • 小项目用 props,简单直接,写起来最舒服;
  • 兄弟多了靠父组件中转,代码清晰不绕弯;
  • 层级深了用 Context,省去 props 层层传递的烦恼;
  • 项目大了就上 Redux,全局管理,谁用谁知道,团队协作更高效!

每种通信方式都有自己的适用场景,没有绝对的“最优解”,只有“最合适”。希望这篇文章能帮你理清思路,下次遇到组件通信问题,别再头大啦!🎉