![低代码平台开发实践:基于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=1739192889-EWMcLdPePYcW4wp73wUUrHWWxpaskAQZ-0-81264b84c1d8c38e08789b381315b1c9)
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=1739192889-oXDZeCZKksIuvtBqdyGAnPmiYGkhUlZg-0-97c59fee33ecc1fd2a4ca43e8173cb81)
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_23_01.jpg?sign=1739192889-TYMNcHQq0D6TuBHHLqml7W6IplbEbbEc-0-6788d4282e31a6629872c9128a09470c)
2.用useReducer实现计数器
要用useReducer就离不开reducer,reducer是一个函数,用于更新useReducer返回的状态。相关代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_23_02.jpg?sign=1739192889-6h2v0cODhbXItxXASyuDZ2jTvIkFdwPw-0-d9003bfb2dbfaddf0c036093466f30ab)
计数器Demo有两个状态,分别是当前值和加减步数,这两个状态密切相关,这里用一个TS接口去描述它们,代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_23_03.jpg?sign=1739192889-iv2mRFxYSza1HiKwLhYTRkbZOTTU9kQc-0-d00e2d21645f44f786ee98da4395f097)
计数器有4种操作,分别是加、减、重置和修改步数,这里用TS接口描述这些行为,代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_24_01.jpg?sign=1739192889-8CJZI00dztbwSXWeBSyt1idTHHRy1bhR-0-5c226783d96681c1109fb9a000664e51)
在组件中使用useReducer的代码如下。
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_24_02.jpg?sign=1739192889-Zih7LNg6TG7AsMJTITrm7HTAHO0X1Kyf-0-5b99985875d4e297ee08f3661171f0e6)
只考虑代码量,读者应该会认为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=1739192889-K9buLYnITyWAp8zKXHHC2fYBsFjHAyDc-0-fdc5a73a3dd53db825319487290b5fa1)
![](https://epubservercos.yuewen.com/10262B/29686504404601406/epubprivate/OEBPS/Images/978-7-111-74689-8_25_01.jpg?sign=1739192889-RNUZdoYynhQp2mX0TIqPDA075eQZfmtv-0-d2bfbe1dc3c9411fca4b68d8d841b72d)
上述代码中useEffect的第二个参数为空数组,这意味着effect只在组件初始渲染时执行。由于React会让dispatch在组件的每次渲染中保持唯一的引用,所以dispatch不必出现在effect的依赖中,此特性与Ref类似。虽然dispatch的引用保持不变,但它能调用组件本次渲染时的reducer,在reducer中能得到最新的状态和props。
注意
可以从依赖中去除dispatch、setState和Ref,因为React会确保它们的引用保持不变。