![低代码平台开发实践:基于React](https://wfqqreader-1252317822.image.myqcloud.com/cover/617/50417617/b_50417617.jpg)
1.3.4 useReducer
useReducer是除useState之外另一个与状态管理相关的Hooks。对于熟悉Redux的工程师而言,理解useReducer会很简单。在React内部,useState由useReducer实现。useReducer的类型定义如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_22_01.jpg?sign=1739507692-ZEvv5XRoNAcXma9I6rLR6ZiEqu8R4kFt-0-972650c9080e1ff2168a8743d165e928)
useReducer的类型定义很复杂,一共有5个重载,总体而言,它最多可接收三个参数。第一个参数是一个用于更新状态的函数,本书将它称为reducer。第三个参数非必填,如果不存在第三个参数,那么第二个参数将作为状态的初始值;如果存在第三个参数,那么它必须是函数,第二个参数被传递给该函数用于计算状态的初始值,该函数只在组件初始渲染时执行一次。useReducer的返回值是一个长度为2的数组,数组的第一个位置是状态值,第二个位置是一个用于触发状态更新的函数,该函数被记为dispatch,调用dispatch将导致reducer被调用。接下来通过计数器示例对比useState和useReducer在用法上的差异。
1.用useState实现计数器
用useState定义两个状态,分别表示计数器的值和步长。完整的代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_22_02.jpg?sign=1739507692-MHlPfvndLuFzYCNSsXmVbFsCji98CJKw-0-565a3ddaed188f2dbca75b24d8c396e8)
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_23_01.jpg?sign=1739507692-rRzvLr9wheU1RqHXLIYOEeTTAJt8e5zM-0-c8a034b09a6ee5b9a92cbe3336537c65)
2.用useReducer实现计数器
要用useReducer就离不开reducer,reducer是一个函数,用于更新useReducer返回的状态。相关代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_23_02.jpg?sign=1739507692-8wjef6Jmb5rFRAYXjCynJkw3dnX5pki1-0-09e5e1b423a5f2957585c9a16f2ff80f)
计数器Demo有两个状态,分别是当前值和加减步数,这两个状态密切相关,这里用一个TS接口去描述它们,代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_23_03.jpg?sign=1739507692-pWeAVHN0x4Cf4PQcxlla0A7OOIMsj5gg-0-a50800a64e7430598ec002ed50ba0d1b)
计数器有4种操作,分别是加、减、重置和修改步数,这里用TS接口描述这些行为,代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_24_01.jpg?sign=1739507692-lEJ4hEiPGINtOcMWo243vv7WK1CXAZwx-0-a4ddafde616e0ac548421e7643f8f134)
在组件中使用useReducer的代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_24_02.jpg?sign=1739507692-ATZ0IiBPiw8cHwBDZU2k2YYPQOVZgm3k-0-79b83570b75327a231b7f6ad3e83a341)
只考虑代码量,读者应该会认为useState比useReducer更简洁。仔细观察可以发现,上述计数器除了有value还有step,step对value有影响。UseStateCounterDemo组件将value和step零散地保存在不同的状态中,然而UseStateCounterDemo组件将它们关联在同一个状态中,内聚性更高。useState与useReducer没有优劣之分,它们有各自适用的场景,这里有如下建议。
❑ 当状态是一个拥有很多属性的复杂对象,并且状态更新涉及复杂的逻辑时,推荐使用useReducer。
❑ 当某个状态的更新受另一个状态影响时,推荐使用useReducer将两个状态放在一起。
❑ 当状态只是单独的基本数据类型时,推荐使用useState。
在介绍useEffect时强调过,为了在effect中拿到状态最新的值,必须给effect设置正确的依赖项。在effect中使用useReducer返回的dispatch能让effect“自给自足”,减少依赖项。示例代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_24_03.jpg?sign=1739507692-jrxfSnIcw2lKUW80oAGkzm8g6sgi8xx8-0-5046c0459f64a1f7bd81abab9dd38252)
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_25_01.jpg?sign=1739507692-gI8tTosjsnhRf2EBSbmZV3hw2315OhdV-0-a7d585cf0978253aa2eddf570f8389c2)
上述代码中useEffect的第二个参数为空数组,这意味着effect只在组件初始渲染时执行。由于React会让dispatch在组件的每次渲染中保持唯一的引用,所以dispatch不必出现在effect的依赖中,此特性与Ref类似。虽然dispatch的引用保持不变,但它能调用组件本次渲染时的reducer,在reducer中能得到最新的状态和props。
注意
可以从依赖中去除dispatch、setState和Ref,因为React会确保它们的引用保持不变。