低代码平台开发实践:基于React
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.3.4 useReducer

useReducer是除useState之外另一个与状态管理相关的Hooks。对于熟悉Redux的工程师而言,理解useReducer会很简单。在React内部,useState由useReducer实现。useReducer的类型定义如下。

useReducer的类型定义很复杂,一共有5个重载,总体而言,它最多可接收三个参数。第一个参数是一个用于更新状态的函数,本书将它称为reducer。第三个参数非必填,如果不存在第三个参数,那么第二个参数将作为状态的初始值;如果存在第三个参数,那么它必须是函数,第二个参数被传递给该函数用于计算状态的初始值,该函数只在组件初始渲染时执行一次。useReducer的返回值是一个长度为2的数组,数组的第一个位置是状态值,第二个位置是一个用于触发状态更新的函数,该函数被记为dispatch,调用dispatch将导致reducer被调用。接下来通过计数器示例对比useState和useReducer在用法上的差异。

1.用useState实现计数器

用useState定义两个状态,分别表示计数器的值和步长。完整的代码如下。

2.用useReducer实现计数器

要用useReducer就离不开reducer,reducer是一个函数,用于更新useReducer返回的状态。相关代码如下。

计数器Demo有两个状态,分别是当前值和加减步数,这两个状态密切相关,这里用一个TS接口去描述它们,代码如下。

计数器有4种操作,分别是加、减、重置和修改步数,这里用TS接口描述这些行为,代码如下。

在组件中使用useReducer的代码如下。

只考虑代码量,读者应该会认为useState比useReducer更简洁。仔细观察可以发现,上述计数器除了有value还有step,step对value有影响。UseStateCounterDemo组件将value和step零散地保存在不同的状态中,然而UseStateCounterDemo组件将它们关联在同一个状态中,内聚性更高。useState与useReducer没有优劣之分,它们有各自适用的场景,这里有如下建议。

❑ 当状态是一个拥有很多属性的复杂对象,并且状态更新涉及复杂的逻辑时,推荐使用useReducer。

❑ 当某个状态的更新受另一个状态影响时,推荐使用useReducer将两个状态放在一起。

❑ 当状态只是单独的基本数据类型时,推荐使用useState。

在介绍useEffect时强调过,为了在effect中拿到状态最新的值,必须给effect设置正确的依赖项。在effect中使用useReducer返回的dispatch能让effect“自给自足”,减少依赖项。示例代码如下。

上述代码中useEffect的第二个参数为空数组,这意味着effect只在组件初始渲染时执行。由于React会让dispatch在组件的每次渲染中保持唯一的引用,所以dispatch不必出现在effect的依赖中,此特性与Ref类似。虽然dispatch的引用保持不变,但它能调用组件本次渲染时的reducer,在reducer中能得到最新的状态和props。

注意

可以从依赖中去除dispatch、setState和Ref,因为React会确保它们的引用保持不变。