组件通信的四大分类
1. 父子组件通信(props + callback)
父组件直接在子组件标签上写属性 ,子组件通过使用
props
接收数据
🌱 父组件向子组件传数据
jsx
// 父组件
function Parent() {
const [message, setMessage] = useState("Hello from Parent")
return (
<div>
<Child message={message} /> //
</div>
)
}
// 子组件
function Child({ message }) {
return <p>{message}</p>
}
🔄 子组件向父组件传数据
父组件在子组件标签上绑定函数,子组件调用函数并将变量作为参数传入该函数
jsx
// 父组件
function Parent() {
const handleChildMessage = (childMsg) => {
alert(`收到子组件的消息:${childMsg}`)
}
return (
<div>
<Child onSendMessage={handleChildMessage} />
</div>
)
}
// 子组件
function Child({ onSendMessage }) {
return (
<button onClick={() => onSendMessage("来自子组件!")}>
发送消息
</button>
)
}
2. 兄弟组件通信(父组件作为中转站)
兄弟组件之间通信的关键点在于在父组件共享状态,可以先子传父组件,再父传子组件
jsx
function Parent() {
const [sharedData, setSharedData] = useState("初始数据") // 父组件中设置共享的状态
return (
<div>
<ChildA onSendData={setSharedData} />
<ChildB sharedData={sharedData} />
</div>
)
}
// 兄弟A发送数据
function ChildA({ onSendData }) {
return (
<input
onChange={(e) => onSendData(e.target.value)}
placeholder="输入数据"
/>
)
}
// 兄弟B接收数据
function ChildB({ sharedData }) {
return <p>共享数据:{sharedData}</p>
}
3. 跨层级通信(Context API)
设组件A是组件B的父组件,组件B是组件C的父组件
要将A中的变量传递给C组件,需要创建全局
Context
组件
- 组件A中使用Context.Provider包裹组件B
- 在C组件中使用
useContext
获取Context组件中的变量
jsx
import { createContext, useContext, useState } from 'react'
const myContext = createContext() // 创建全局的Context进行数据的传递
function B () { // 孙子组件
const msg = useContext(myContext) // 获取父组件传递的值
return (
<div>
<h3>Component B --{msg}</h3>
</div>
)
}
function A () { // 子组件
const msg = useContext(myContext) // 获取父组件传递的值
return (
<div>
<h1>Component A --{msg}</h1>
<B/>
</div>
)
}
function Index () { // 父组件
const [msg, setMsg] = useState('Hello from Grandparents')
return (
<div>
<myContext.Provider value={msg}>
<A/>
</myContext.Provider>
</div>
)
}
4. 任意组件通信(全局仓库)
在面对完全没有父子或者层级关系的组件之间进行通信的情况时,上述的三种方法就会显得鸡肋和乏力。如果硬要用这种方法写代码会极其冗杂,难以维护。这个时候就需要全局仓库了。各个组件即用即取,仓库对状态进行统一管理。不需要多余的代码和心智负担。
全局仓库的优势
-
解决跨组件通信复杂性
- 在大型应用中,组件层级深、关系复杂时,直接通过
props
传递状态(Prop Drilling)会导致代码臃肿、难以维护。 - 全局仓库提供统一的状态访问入口,避免逐层传递状态或回调函数。
- 在大型应用中,组件层级深、关系复杂时,直接通过
-
集中管理共享状态
- 所有组件都可以直接从全局仓库读取或更新状态,避免状态分散在多个组件中,降低耦合度。
-
支持复杂业务逻辑
- 全局仓库可以处理异步操作(如 API 请求)、中间件逻辑(如日志记录、权限控制)等,适合需要复杂状态管理的场景。
-
提高可维护性和可测试性
- 全局状态的变更集中管理,便于调试和单元测试,代码结构更清晰。
-
统一状态源
- 所有组件共享一个真实的状态源,避免数据不一致(如多个组件修改同一状态导致冲突)。
全局的状态管理仓库目前有非常多,不论是官方打造的
Redux
还是第三方封装的仓库例如Zustand
、mobx
、valtio
。笔者偏向使用
Zustand
,所以后文的分析将围绕Redux
和Zustand
展开
🧩 Zustand 和 Redux 仓库详解 -- 以计数器为例
一、Redux仓库
@reduxjs/toolkit
(创建子模块仓库)- 创建一个总仓库,在总仓库中注册各个子模块,子模块通常在
modules
目录下 react-redux
(在根组件中连接仓库和react
)- 在组件中使用
useSelector
获取仓库中的数据 - 在组件中使用
useDispatch
获取仓库中的函数 - 调用仓库中的方法 得到一个
action
行为 - 调用
dispatch
函数将action
行为派发给仓库
Redux使用时目录结构示例
bash
深色版本
src/
├── modules/
│ └── counterSlice.js # 子模块
├── store.js # 总仓库
├── App.jsx # 根组件
└── Counter.jsx # 使用状态的组件
Redux 的经典流程
🛠️ 1. 创建 Slice--创建子模块
jsx
// counterSlice.js 步骤 1 -- 创建仓库的子模块:
import { createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment(state) {
state.count += 1
},
decrement(state) {
state.count -= 1
}
}
})
export const { increment, decrement } = counterSlice.actions
export default counterSlice.reducer
🧱 2. 配置 Store
jsx
// store.js 步骤 2: 创建一个总仓库,在总仓库中注册各个子模块
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
const store = configureStore({
reducer: {
counter: counterReducer
}
})
export default store
🔗 3. 在根组件中连接仓库--使仓库全局可用(App.jsx
)
jsx
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';
const App = () => (
<Provider store={store}>
{/* 使用Provider包裹App组件,传入store */}
<Counter />
</Provider>
);
export default App;
🧩 4. 组件中使用仓库
jsx
// Counter.js
// 步骤 2:连接仓库和`react`
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement } from './counterSlice'
function Counter() {
// 步骤 4:使用 useSelector 获取状态
const count = useSelector(state => state.counter.count)
// 步骤 5:使用 useDispatch 获取 dispatch 函数
const dispatch = useDispatch()
// 步骤 6-7:调用 action 并 dispatch
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch(increment())}>+1</button>
<button onClick={() => dispatch(decrement())}>-1</button>
</div>
)
}
二、Zustand 仓库
zustand
(创建状态仓库)- 不需要额外库 (Zustand 天然支持 React,无需像
react-redux
) - 创建一个总仓库,在总仓库中可以组合多个子模块或功能,通常将子模块放在
stores
或modules
目录下 - 在组件中使用
useStore
获取仓库中的数据 - 在组件中直接调用
useStore
返回的actions
(或方法)来修改状态 - 调用仓库中的方法,直接修改状态(Zustand 中不需要
action
和dispatch
) - Zustand 中状态修改是直接的,不需要
dispatch
,调用方法即刻更新状态
Zustand 项目目录结构示例
bash
src/
├── stores/ # 所有 Zustand 仓库存放的目录
│ └── counterStore.js # 示例:计数器模块
├── App.jsx # 根组件
└── Counter.jsx # 使用状态的组件
Zustand 的使用流程
1. 创建状态仓库(核心步骤)
jsx
// counterStore.js
import create from 'zustand'
export default const counterStore = create(set => ({
// 🎯 初始状态
count: 0,
// 🛠️ 修改状态的方法
increment: () => set(state => ({ count: state.count + 1 })),
decrement: () => set(state => ({ count: state.count - 1 }))
}))
📌 步骤拆解:
create()
是 Zustand 的魔法工厂set
是状态修改的钥匙🔑- 返回对象包含:
- ✅ 初始状态(
count
) - ✅ 修改方法(
increment
,decrement
)
- ✅ 初始状态(
2. 组件中使用状态(实战演示)
jsx
// Counter.jsx
import { useCounterStore } from '../stores/counterStore.js'
function Counter() {
// 🧾 获取状态和方法
const { count, increment, decrement } = useCounterStore()
return (
<div>
<p>{count}</p>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
</div>
)
}
💡 小贴士:
useCounterStore()
直接返回整个 store 的状态和方法- 所有组件调用同一个 store 都会自动同步更新✨
🧪 Zustand 与 Redux 对比(重点篇)
1. Zustand 的核心优势
超轻量 API
- 创建 store :
create(set => ({ ... }))
- 使用 store :
const useStore = create(...)
直接返回 hook - 无中间层 :不需要
Provider
或connect
,直接调用 hook
3. Zustand vs Redux 对比表
特性 | Zustand | Redux Toolkit |
---|---|---|
学习成本 | 🟢 更简单,适合新手 | 🔵 需要理解中间件、action、reducer 等概念 |
API 设计 | ✨ 直接使用 hook,无需 Provider | 🧩 需要 Provider 和 connect |
模块化 | 🧩 自动模块化,每个 store 独立 | 🧱 需要手动拆分多个 slice |
异步操作 | 🚀 可直接在 action 中写 async/await | ⚙️ 需要配合 createAsyncThunk |
性能优化 | 🚀 自动订阅,无需 createSelector | ⚙️ 需要 createSelector 优化选择器 |
适合场景 | 🚀 小型项目、快速原型开发 | 🧱 大型复杂应用 |
🧠 总结:选择最适合的方案
- 小型项目 :优先使用 Zustand,代码简洁,上手快
- 中型项目:Zustand + Context API 可以替代 Redux
- 大型项目:Redux Toolkit 提供更完善的工具链
- 跨组件通信:Zustand 的 hook 设计天然支持全局状态共享
通过灵活组合这些工具,可以高效管理复杂应用的状态,同时保持代码的简洁和可维护性!💡