useReducer 是 React 提供的状态管理 Hook,适合处理复杂状态逻辑 。很多场景用 useState 能写,但随着状态增多、更新规则复杂,代码会变乱,这时候 useReducer 更适合。
一、useReducer 基础概念
语法:
scss
const [state, dispatch] = useReducer(reducer, initialState);
参数:
state:当前状态dispatch(action):触发更新reducer:状态处理函数initialState:初始值
类似 Redux:
javascript
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, {
count: 0
});
return (
<>
<p>{state.count}</p>
<button
onClick={() =>
dispatch({ type: 'increment' })
}
>
+
</button>
<button
onClick={() =>
dispatch({ type: 'decrement' })
}
>
-
</button>
</>
);
}
二、什么时候 useState 不够用了?
场景1:多个相关状态一起维护(推荐 useReducer)
useState 写法
例如登录表单:
scss
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
提交:
scss
setLoading(true);
api.login()
.then(() => {
setLoading(false);
})
.catch(() => {
setError('失败');
setLoading(false);
});
状态多时:
go
username
password
loading
error
success
token
userInfo
会越来越乱。
useReducer:
go
const initialState = {
username: '',
password: '',
loading: false,
error: ''
};
function reducer(state, action) {
switch (action.type) {
case 'SET_USERNAME':
return {
...state,
username: action.payload
};
case 'LOGIN_START':
return {
...state,
loading: true
};
case 'LOGIN_FAIL':
return {
...state,
loading: false,
error: action.payload
};
default:
return state;
}
}
const [state, dispatch] =
useReducer(reducer, initialState);
更新:
php
dispatch({
type: 'SET_USERNAME',
payload: '张三'
});
逻辑集中。
适合:
✅ 表单
✅ 登录流程
✅ 搜索筛选条件
✅ 弹窗状态
场景2:状态之间有关联
例如购物车:
状态:
商品数量
总价
优惠金额
是否可提交
如果:
scss
setCount()
setPrice()
setDiscount()
setCanSubmit()
可能出现更新不同步。
用 reducer:
javascript
function reducer(state, action) {
switch(action.type){
case 'ADD_PRODUCT':
const count =
state.count + 1;
return {
count,
total:
count * state.price,
canSubmit:
count > 0
}
}
}
一次更新全部状态。
适合:
购物车
订单
配置面板
步骤流
场景3:状态更新逻辑复杂
例如:
性能平台筛选条件:
云厂商
CPU架构
规格
产品代际
核数
自动联动
你之前做过类似:
选择 CPU → 自动填规格 → 自动填云厂商
多个接口联动:
选择规格
↓
请求接口
↓
更新5个状态
↓
重置表单
这类就适合 reducer:
php
dispatch({
type:'UPDATE_FILTER',
payload:data
})
统一管理。
场景4:状态机(步骤流)
例如:
上传文件:
go
idle
uploading
success
error
useReducer:
matlab
function reducer(state, action) {
switch(action.type){
case 'UPLOAD':
return {
status:'loading'
}
case 'SUCCESS':
return {
status:'success'
}
case 'FAIL':
return {
status:'error'
}
}
}
比:
go
loading
success
error
多个 bool 更清晰。
适合:
上传
支付
审批流
登录
任务执行
场景5:多人协作,希望逻辑统一
useState
更新散落:
scss
setA()
setB()
setC()
难找。
useReducer
统一:
bash
dispatch({
type:'UPDATE_USER'
})
所有更新都进 reducer。
维护成本低。
三、什么时候不要用 useReducer?
简单状态:
arduino
const [visible, setVisible]
const [count, setCount]
const [name, setName]
没必要:
scss
useReducer()
会增加复杂度。
建议:
| 状态复杂度 | 推荐 |
|---|---|
| 1~2 个简单状态 | useState |
| 多个相关状态 | useReducer |
| 状态联动 | useReducer |
| 复杂业务流程 | useReducer |
| 状态机 | useReducer |
| 大型组件 | useReducer |
| 全局状态 | useReducer + Context |
四、和 Redux 区别
很多人第一次看到:
scss
dispatch()
reducer()
action.type
以为 Redux。
其实:
Redux:
全局状态
所有组件共享
useReducer:
组件内部状态
局部状态管理
组合使用:
Context + useReducer
≈ 简化版 Redux
适合中小项目。
可以记一句经验:
useState管"值",useReducer管"状态变化规则"。
当你发现组件里出现很多:
scss
setA()
setB()
setC()
setD()
或者多个状态互相影响时,就可以考虑换 useReducer。这在你做性能平台那种"筛选条件联动 + 接口回填"的页面,会比多个 useState 更容易维护。