在 React 开发中,组件是构建用户界面的基本单元,而组件之间如何传递数据、协调行为,就是“组件通信”要解决的核心问题。
本文将系统梳理 React 中的组件通信方式,覆盖父子、兄弟、跨层级及全局通信的常见模式,并结合实际代码案例帮助你构建更清晰、健壮的组件架构。
🎯 为什么组件通信如此重要?
React 推崇单向数据流,数据从上往下传,事件从下往上传。小项目中,props 和回调足以满足通信需求;但随着项目规模变大,组件结构复杂、嵌套层级变深,“通信”的复杂度也会指数级上升。
掌握多种通信方式,可以让你:
- 更灵活地组织组件层级
- 更清晰地分离逻辑与展示
- 更高效地维护大型项目的状态管理
🧱 1. 父子通信:props 与回调函数
这是最基础也是最推荐的通信方式,React 的单向数据流模型就是以它为核心。
✅ 父传子(props)
通过 props 将数据传递给子组件,子组件仅负责展示。
function Child({ message }) {
return <p>{message}</p>;
}
function Parent() {
return <Child message="Hello from Parent" />;
}
✅ 子传父(回调函数)
子组件调用父组件传入的函数,实现事件的上抛。
function Child({ onClick }) {
return <button onClick={() => onClick("Clicked from Child")}>Click</button>;
}
function Parent() {
const handleChildClick = (msg) => {
console.log(msg);
};
return <Child onClick={handleChildClick} />;
}
📌 适用场景:结构清晰、数据流简单的父子组件。
🤝 2. 兄弟组件通信:通过共同父组件中转
兄弟组件之间无法直接通信,需要通过它们的共同父组件作为“中介”。
function SiblingA({ send }) {
return <button onClick={() => send("Message from A")}>Send</button>;
}
function SiblingB({ message }) {
return <p>Received: {message}</p>;
}
function Parent() {
const [msg, setMsg] = useState("");
return (
<>
<SiblingA send={setMsg} />
<SiblingB message={msg} />
</>
);
}
📌 适用场景:兄弟组件间需要传递信息,且共享同一父组件。
🌐 3. 跨层级通信:使用 React Context
当子组件嵌套层级很深时,逐层通过 props 传递就会变得非常繁琐。这时候就可以使用 React.createContext 实现跨层数据共享。
✅ 创建上下文并提供数据:
jsx
const UserContext = createContext(null);
function App() {
const user = { name: "Jiang", role: "admin" };
return (
<UserContext.Provider value={user}>
<Layout />
</UserContext.Provider>
);
}
✅ 任意深层组件中消费:
function UserInfo() {
const user = useContext(UserContext);
return <p>当前用户:{user.name}</p>;
}
📌 适用场景:全局主题、用户信息、语言包、权限管理等。
🧩 4. 任意组件通信:使用全局状态管理工具
当通信对象之间没有父子关系,也没有共同祖先,或数据共享范围扩大到整个应用时,就需要使用专门的状态管理库。
✅ Redux 示例(也可用 Zustand、Jotai 等)
// counterSlice.js
const initialState = { count: 0 };
function reducer(state = initialState, action) {
if (action.type === "increment") return { count: state.count + 1 };
return state;
}
// CounterA.jsx
const count = useSelector((state) => state.count);
// CounterB.jsx
const dispatch = useDispatch();
<button onClick={() => dispatch({ type: "increment" })}>+</button>;
📌 适用场景:跨模块、跨页面、跨组件的大型应用状态通信。
🔁 5. 轻量通信:事件总线(Event Bus)
对于不适合用 Redux 的项目中,可以自定义一个事件中心,在任意组件之间派发和监听事件。
// eventBus.js
const eventBus = {
events: {},
on(event, fn) {
(this.events[event] ||= []).push(fn);
},
emit(event, data) {
(this.events[event] || []).forEach(fn => fn(data));
}
};
export default eventBus;
使用:
// A 组件
eventBus.emit("sendMsg", "Hello");
// B 组件
useEffect(() => {
eventBus.on("sendMsg", (msg) => console.log(msg));
}, []);
📌 适用场景:页面间解耦、动态弹窗控制、独立组件通信等。
🔧 6. Hook 通信:自定义 Hook 共享逻辑状态
把共享逻辑封装到一个 Hook 中,在多个组件中调用这个 Hook 实现“间接通信”。
// useCounter.js
let count = 0;
const listeners = new Set();
export function useCounter() {
const [value, setValue] = useState(count);
useEffect(() => {
listeners.add(setValue);
return () => listeners.delete(setValue);
}, []);
const increment = () => {
count += 1;
listeners.forEach(fn => fn(count));
};
return { value, increment };
}
多个组件中使用后即可实时同步:
const { value, increment } = useCounter();
📌 适用场景:多个组件共享状态但不想引入全局库的轻量项目。
📊 通信方式对比总结
- props / 回调:结构简单,推荐优先使用
- context:解决 props drilling,适合共享配置
- 状态管理库:适合大规模状态同步(Redux、Zustand 等)
- 事件总线:组件完全解耦,适合临时广播通信
- 自定义 hook:复用状态逻辑,适合中小型模块共享
🧠 最佳实践建议
- 优先使用 props 回调,保持数据流简洁可控
- 跨层嵌套多时用 Context,避免 props drilling
- 复杂状态共享用 Zustand/Redux,避免重复逻辑
- 轻耦合需求用事件总线/Hook 更灵活
- 保持通信“最小必要”,过度通信会导致维护困难
🧩 写在最后
组件间通信,是 React 架构设计中非常关键的一环。从最基础的 props,到跨层 Context,再到状态管理系统、事件机制,每一种通信方式都对应着不同的项目复杂度和场景需求。
掌握它们的原理与最佳实践,能让你的组件更清晰,项目结构更可控。