React 组件通信方式详解(含示例与优缺点)

📘 React 组件通信方式详解(含示例与优缺点)

本文将系统总结 React 项目中常见的组件通信方式,包括 props、Context、ref、事件总线、全局状态管理等,帮助你根据不同场景选择最合适的方式。


📌 1. 父子组件通信:props

父组件通过 props 向子组件传递数据或回调函数。

示例:
// 子组件 Child.tsx
const Child = ({ message, onReply }: { message: string; onReply: (text: string) => void }) => {
  return (
    <div>
      <p>子组件收到:{message}</p>
      <button onClick={() => onReply('你好,父组件!')}>回复</button>
    </div>
  );
};

// 父组件 Parent.tsx
const Parent = () => {
  const handleReply = (msg: string) => {
    console.log('收到子组件回复:', msg);
  };

  return <Child message="你好,子组件" onReply={handleReply} />;
};
✅ 优点:
  • 简单直观,符合组件化思想
  • 类型可控,利于维护
❌ 缺点:
  • 只能用于父子或祖孙组件
  • 多层传递时繁琐(props drilling)

📌 2. 兄弟组件通信:状态提升 + 共享父组件

兄弟组件无法直接通信,需要通过共同父组件中转。

示例:
// Parent.tsx
const Parent = () => {
  const [data, setData] = useState('从A来');

  return (
    <>
      <ComponentA send={(val) => setData(val)} />
      <ComponentB msg={data} />
    </>
  );
};

const ComponentA = ({ send }: { send: (val: string) => void }) => {
  return <button onClick={() => send('来自A的消息')}>发送</button>;
};

const ComponentB = ({ msg }: { msg: string }) => {
  return <p>ComponentB收到:{msg}</p>;
};
✅ 优点:
  • 数据集中在父组件,逻辑清晰
  • 无需引入额外库
❌ 缺点:
  • 耦合度高,父组件容易膨胀
  • 不适合深层组件结构

📌 3. 跨层通信:Context API

用于共享全局数据,避免 props 层层传递。

示例:
// context.ts
export const ThemeContext = createContext('light');

// 父组件
const App = () => (
  <ThemeContext.Provider value="dark">
    <Child />
  </ThemeContext.Provider>
);

// 子孙组件
const Child = () => {
  const theme = useContext(ThemeContext);
  return <p>当前主题:{theme}</p>;
};
✅ 优点:
  • 解决 props drilling 问题
  • 原生支持,无需第三方库
❌ 缺点:
  • 不适合频繁变化的数据(如表单状态)
  • 多个 Context 嵌套时难以管理

📌 4. 不相关组件通信:事件总线(Event Bus)

使用自定义事件系统(如 mitt)实现松耦合通信。

示例(基于 mitt):
npm install mitt
// eventBus.ts
import mitt from 'mitt';
export const bus = mitt();

// 发送组件 A.tsx
bus.emit('send-msg', '来自A的消息');

// 接收组件 B.tsx
useEffect(() => {
  const handler = (msg: string) => console.log('B收到:', msg);
  bus.on('send-msg', handler);
  return () => bus.off('send-msg', handler);
}, []);
✅ 优点:
  • 解耦、灵活,适合全局广播
  • 非父子组件也能通信
❌ 缺点:
  • 可读性差,不利于追踪数据流
  • 易引起内存泄漏、调试困难

📌 5. 全局状态通信:Redux / Zustand / Recoil

用于大型项目中跨组件共享和管理复杂状态。

示例(Zustand):
npm install zustand
// store.ts
import { create } from 'zustand';

export const useUserStore = create((set) => ({
  name: '张三',
  setName: (name: string) => set({ name }),
}));

// A组件修改
useUserStore().setName('李四');

// B组件读取
const name = useUserStore().name;
示例(Redux ):

首先安装所需依赖:

npm install @reduxjs/toolkit react-redux

🧩 项目结构

src/
├── app/
│   └── store.ts        ← Redux Store 配置
├── features/
│   └── counter/
│       ├── counterSlice.ts   ← 状态切片
│       └── Counter.tsx       ← 示例组件
├── App.tsx
└── main.tsx (或 index.tsx)

1️⃣ 创建 Store(store.ts

// src/app/store.ts
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

// 推导 RootState 和 AppDispatch 类型
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

2️⃣ 定义 Slice(counterSlice.ts

// src/features/counter/counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface CounterState {
  value: number;
}

const initialState: CounterState = {
  value: 0,
};

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

3️⃣ 使用 Provider 包裹应用(main.tsx

// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import { store } from './app/store';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

4️⃣ 在组件中使用 Redux(Counter.tsx

// src/features/counter/Counter.tsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState, AppDispatch } from '../../app/store';
import { increment, decrement, incrementByAmount } from './counterSlice';

const Counter = () => {
  const count = useSelector((state: RootState) => state.counter.value);
  const dispatch = useDispatch<AppDispatch>();

  return (
    <div>
      <h2>计数器:{count}</h2>
      <button onClick={() => dispatch(decrement())}>-1</button>
      <button onClick={() => dispatch(increment())}>+1</button>
      <button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
    </div>
  );
};

export default Counter;

5️⃣ App 中使用组件(App.tsx

// src/App.tsx
import React from 'react';
import Counter from './features/counter/Counter';

function App() {
  return (
    <div style={{ padding: '2rem' }}>
      <h1>Redux Toolkit 示例</h1>
      <Counter />
    </div>
  );
}

export default App;

✅ 输出结果

Redux Toolkit 示例
计数器:0
[ -1 ] [ +1 ] [ +5 ]

点击按钮即可修改 Redux 中的全局状态,并在组件中响应。

✅ 优点:
  • 统一状态源,便于管理
  • 可用于大型应用、多人协作
❌ 缺点:
  • 学习成本略高
  • 对小项目而言可能过重

✅ 总结表格

通信方式适用场景优点缺点
props父子组件简单直观、可控性强层层传递繁琐
状态提升兄弟组件结构清晰父组件易臃肿
Context跨层级祖孙组件解决深层传递问题不适合频繁变化的状态
事件总线不相关组件通信解耦灵活不可追踪,易出 bug
全局状态管理大型项目,复杂数据共享状态集中、调试方便引入成本高,小项目不推荐

🧠 写在最后

组件通信方式没有好坏,只有适不适合你的业务场景。小项目用 props + context 足够,大型项目配合 Zustand/Redux 更高效。

如果你有更优的实践,欢迎留言交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值