首发于 Good Morning
React Hooks: useState 和 useReducer 有什么区别?

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 (