React-状态管理器:zustand vs react-redux
分类: React 23 0
组件通信的四大分类
1. 父子组件通信(props + callback)
> 父组件直接在子组件标签上写属性,子组件通过使用props
接收数据
🌱 父组件向子组件传数据
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
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
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. **任意组件通信(全局仓库)**
在面对完全没有父子或者层级关系的组件之间进行通信的情况时,上述的三种方法就会显得鸡肋和乏力。如果硬要用这种方法写代码会极其冗杂,难以维护。这个时候就需要全局仓库了。各个组件即用即取,仓库对状态进行统一管理。不需要多余的代码和心智负担。
#### 全局仓库的优势
1. **解决跨组件通信复杂性**
- 在大型应用中,组件层级深、关系复杂时,直接通过 props
传递状态(Prop Drilling)会导致代码臃肿、难以维护。
- **全局仓库**提供统一的状态访问入口,避免逐层传递状态或回调函数。
1. **集中管理共享状态**
- 所有组件都可以直接从全局仓库读取或更新状态,避免状态分散在多个组件中,降低耦合度。
1. **支持复杂业务逻辑**
- 全局仓库可以处理异步操作(如 API 请求)、中间件逻辑(如日志记录、权限控制)等,适合需要复杂状态管理的场景。
1. **提高可维护性和可测试性**
- 全局状态的变更集中管理,便于调试和单元测试,代码结构更清晰。
1. **统一状态源**
- 所有组件共享一个真实的状态源,避免数据不一致(如多个组件修改同一状态导致冲突)。
> 全局的状态管理仓库目前有非常多,不论是官方打造的Redux
还是第三方封装的仓库例如Zustand
、mobx
、valtio
。
---
## 🧩 Zustand 和 Redux 仓库详解 -- 以计数器为例
### 一、Redux仓库
1. @reduxjs/toolkit
(创建子模块仓库)
1. 创建一个总仓库,在总仓库中注册各个子模块,子模块通常在modules
目录下
1. react-redux
(在根组件中连接仓库和react
)
1. 在组件中使用useSelector
获取仓库中的数据
1. 在组件中使用useDispatch
获取仓库中的函数
1. 调用仓库中的方法 得到一个action
行为
1. 调用dispatch
函数将action
行为派发给仓库
---
> Redux使用时目录结构示例
```bash
src/
├── modules/
│ └── counterSlice.js # 子模块
├── store.js # 总仓库
├── App.jsx # 根组件
└── Counter.jsx # 使用状态的组件
Redux 的经典流程
🛠️ 1. 创建 Slice--创建子模块
```jsx
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
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
const store = configureStore({
reducer: {
counter: counterReducer
}
})
export default store
🔗 3. 在根组件中连接仓库--使仓库全局可用(`App.jsx`)
```jsx
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
// 步骤 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
├── stores/ # 所有 Zustand 仓库存放的目录
│ └── counterStore.js # 示例:计数器模块
├── App.jsx # 根组件
└── Counter.jsx # 使用状态的组件#### **Zustand 的使用流程** #### 1. 创建状态仓库(核心步骤) ```jsx 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 }))
}))
📌 **步骤拆解**:
1. `create()` 是 Zustand 的魔法工厂
1. `set` 是状态修改的钥匙🔑
1. 返回对象包含: - ✅ 初始状态(`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 优化选择器 适合场景 🚀 小型项目、快速原型开发 🧱 大型复杂应用
🧠 总结:选择最适合的方案
- 使用 store:
-
小型项目:优先使用 Zustand,代码简洁,上手快
- 中型项目:Zustand + Context API 可以替代 Redux
- 大型项目:Redux Toolkit 提供更完善的工具链
- 跨组件通信:Zustand 的 hook 设计天然支持全局状态共享
共 0 条评论关于 “React-状态管理器:zustand vs react-redux”