反应革命:解放React中的副作用函数,解决心智负担难题

在 React 开发中,我们经常面临三个心智负担:保证状态的不可变性、正确执行副作用以及规避不必要的渲染。副作用函数是其中一个最大的挑战,当副作用开始执行时,不确定性因素会呈指数型增长,导致开发过程中需要小心谨慎,否则可能出现奇奇怪怪、难以排查的问题。然而,通过使用两个特殊的 React hook:useSyncState 和 useSyncMemo,我们可以显著改善开发体验并消除副作用函数的复杂性。
在本文中,我们将详细介绍 useSyncState 和 useSyncMemo 的用法,以及它们如何帮助我们消除副作用函数,同时满足 React 的开发规则。我们将使用一个名为 react-sync-state-hook 的库来获得这两个 hook,你可以通过 npm 来安装它。
首先,我们来了解 useSyncState 的原理。该 hook 很简单,它通过一个变量保存状态的最新值,并生成一个不可变数据代理返回。在重新渲染前,我们可以通过该数据代理来获取新状态的副本。下面是 useSyncState 的用法:
在上面的例子中,A 和 setA 的用法与平常使用的 state 和 setState 并无二致,而 curA 则是保存最新状态值的副本。它是一个不可变数据的代理,类似于 immer 的 draft。因此,对 curA 进行的任何修改都不会对状态产生影响。我们可以遵循状态不可变的原则来修改状态,示例如下:
无需担心传进去的 curA.current 是一个代理对象,因为在 setA 的内部会自动将其解包,状态值将被赋予解包后的数据。setA 也支持函数式更新,其参数是一个不可变数据代理,并且无需通过 .current 调用,类似于 useImmer 的用法。
接下来,我们介绍 useSyncMemo 的原理。该 hook 通过订阅 currentState 的 getter 和 setter,来感知依赖项的变化,从而计算得到重新渲染前的 memo 值。因此,如果需要显式传递依赖项,我们需要使用 currentState 作为依赖项。用法如下:
注意:计算函数里只有使用 curA 去计算才能得到实时的 curM。在没有显式传递依赖项的情况下,useSyncMemo 内部会通过 curA 的 getter 去获取依赖项。
这两个 hook 的特点让我们能够在重新渲染前获取到最新的状态值和计算值,从而消除副作用函数的复杂性。举个例子来说明,假设我们有两个异步请求去获取状态 A 和 B 的值,然后根据它们的值做一些计算。我们可以使用 useSyncState 和 useSyncMemo 来优化这个过程,示例代码如下:
通过这样的写法,我们可以保证在两个异步请求之后,根据 A 和 B 的值执行副作用函数 todos(),而且计算次数减少到 1 次,不论后面我们新增多少个状态,都只会计算一次,避免了冗余的计算。
总结一下,使用 useSyncState 和 useSyncMemo 可以显著减少 React 开发中的心智负担,消除副作用函数的复杂性,并且提高性能。通过消除副作用,我们可以更自由地在组件中执行副作用操作,而无需担心依赖问题。同时,这两个 hook 还能帮助我们遵循状态不可变性原则,从而更好地管理状态的变更。如果你之前的 React 开发经验与这种方式有所不同,不妨试试使用这两个 hook,相信对你会有一定的帮助。

转载 / 合作
请联系