React Hooks: useState 和 useReducer 有什么区别?
语雀地址: React Hooks: useState 和 useReducer 有什么区别? · 语雀
setState 和 useReducer 的功能很类似,都是状态管理,理论上他们两个的功能是用另一个可以代替的。为什么 React 要提供这样两个功能有重叠的 API 呢?
useState:细粒度的状态管理
从官方文档来看,useState 相当于类组件的 setState,存在的目的都是拿来做组件内的状态管理。
只不过一个类组件只有一个 setState,但是一个函数组件却可以有很多 useState,这让我们可以把独立的状态分开管理,逻辑上更清晰了,更方便维护了,这是 hooks 的天然优势。
// ************ setState ************
class Test extends React.Component {
state = {
a: '1',
b: '2',
handler() {
// ... 处理 a
const newA = transferA(this.state.a);
// ...处理 b
const newB = transferB(this.state.b);
this.setState({
a: newA,
b: newB,
// ************ useState ************
function useA() {
const [a, setA] = useState('1');
const handlerA = () => {
// ... 处理 a
const newA = TransferA(a);
setA(newA);
return { a, handlerA };
function useB() {
const [b, setB] = useState('2');
const handlerB = () => {
// ... 处理 a
const newB = TransferA(b);
setB(newB);
return { b, handlerB };
function Test() {
const { a, handlerA } = useA();
const { b, handlerB } = useB();
const handler = () => {
handlerA();
handlerB();
return ...
上面的代码对比很明显,从 setState 到 useState 之后,可能总的代码行数增加了,但是当你关注于某个 state 的时候,需要关心的代码其实变少了。hooks 最大的好处是让开发者可以做更细粒度的模块化。
useReducer:低成本的数据流
虽说 useReducer 可以拿来做组件内状态管理,但是 useReducer 对于单组件来说太重了,绝大多数情况下是用用不到的。
useReducer 更适合拿来做简单场景下的数据流。useReducer 是阉割版的 redux,只缺了一个状态共享能力,用 hooks 的 useContext 刚刚好。
官方文档中推荐的使用场景是“deep update”,从某种程度来说就是一个局部数据流:
function Parent() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<context.Provider value={dispatch}>
<DeepTree />
</context.Provider>
}
如果该数据流中也要用到 state,可以把 state 和 dispatch 用两个 context 往下传递,原因是这样可以避免只依赖了 dispatch 的组件受到 state 更新的影响。
function Parent() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<context1.Provider value={state}>
<context2.Provider value={dispatch}>
<DeepTree />
</context2.Provider>
</context1.Provider>
}
从上面两端代码就可以看出,在函数组件中实现一套看起来还可以的数据流是一件很简单的事情。
这可能是 hooks 比起类组件另一个最亮眼的地方,而且配合 hooks 的自由组合能力,天然把 redux 那坨令人费解的中间件能力给支持了,说实话我看到 redux 的中间件就头秃。
两者的关系
是不是发现 useState 的功能就是 useReducer 的子集?实际上,在 React 内部,useState 就是用 useReducer 实现的,useState 返回的函数内部封装了一个 dispatch。
如果你有兴趣,可以自己动手用 useReducer 实现一个 useCustomState:
function useCustomState(initialState) {
// 特殊的 reducer
const reducer = (action, state) => {
if (typeof action === 'function') {
return action(state);
return action;
const [state, dispatch] = useReducer(reducer, initialState);
// setState 和 dispatch 一样引用也不变的
const setState = useCallback(action => {
dispatch(action);
}, []);
return [state, setState];
// 使用 useCustomState
function Parent() {
const [count, setCount] = useCustomState(0);
return (