useState和useReducer有啥区别?

142 阅读3分钟

大家好,我是前端理想哥,今天,我们来聊聊useStateuseReducer的区别。

先说结论:useState和useReducer都是用于函数组件内部定义状态的,区别在于,useState用于简单的状态管理和局部状态更新,而useReducer用于复杂的状态逻辑和全局状态管理。

对于简单的状态值定义,可以用 useState,如果状态值的修改逻辑比较复杂,你想要抽离出来或者进行复用,那么就可以使用useReducer。

useState实际是一个自带了reducer功能的useReducer语法糖。

我们先来看看这两者的使用,useState的使用方法如图所示:

const [state, setState] = useState(initialState);

图中的用法大家可以看到,useState只接收一个参数,而对于initialState的取值,我们可以一起来看看useState的源码

function mountState<S>(
  initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {
  const hook = mountWorkInProgressHook();

  // useState的初始值
  if (typeof initialState === 'function') {
    initialState = initialState();
  }
  
  // 后续操作
}

大家可以看关键源码,函数一开始时候会判断 initialState 的类型,如果是 function,则会执行,然后把执行结果重新赋值给initialState。

所以,从这里我们可以看出 initialState 可以是一个具体的值,也可以是一个函数

接下来,我们看看useReducer的用法

const [state, dispatch] = useReducer(reducer, initialState, init);

对于图中的用法,大家可以看到,会接收三个参数,第一个参数是一个函数,第二个是一个初始值,第三个参数init应该很多朋友都不了解,没关系,我们通过源码来看下:

function mountReducer<S, I, A>(
  reducer: (S, A) => S,
  initialArg: I,
  init?: I => S,
): [S, Dispatch<A>] {
  const hook = mountWorkInProgressHook();
  let initialState;

  // useReducer的初始值
  if (init !== undefined) {
    initialState = init(initialArg);
  } else {
    initialState = ((initialArg: any): S);
  }

  // 后续操作
}

大家可以看关键源码,如果init参数存在,则会用init来处理初始值initialArg,然后把处理结果重新传给initialState。

所以,从这里我们可以看到 init 其实是一个函数,作用是在初始时候,对你传入的初始值进行处理的。比如你传了个初始值,但是不是你想要的,得用一个函数处理下,那你就可以把这个函数作为第三个参数传入,useReducer中会自动进行处理的。

除了上面用法的区别外,其实还有一个非常重要的区别,那就是这两者在组件更新方面的区别。

当你使用useState时,如果state没有发生变化,那么组件就不会更新。而使用了useReducer时,在state没有发生变化时,组件依然会更新。大家在使用时候,千万要注意这点的区别。

以上,就是所有内容了,我们讲了useState和useReducer的用法以及区别,如果您觉得文章对您有帮助,欢迎给理想哥一个关注,万分感谢大家,也可以私聊理想哥加入前端岗位内推群,我们会经常在群里发布各大公司急招岗位和面试求职经验,帮助大家尽快的找到工作。