为什么你应该选择useState代替useReducer呢

导游通过useState局部和全局状态管理

自从引入反应hook API,我见过很多讨论useState,useReducer,当使用一种。从这些对话,人会得出结论useState最适合简单的状态和简单的更新逻辑useReducer最适合复杂形状和复杂的更新逻辑状态。

我来说服你当包裹在4线定制钩,useState可以一样强大,如果不是更强大的比,useReducer在管理复杂的状态。

我不喜欢还原剂。我试着使用它们,但我总是最终迁移。一些关于调度操作会有问题时触发业务逻辑可以通过调用一个函数与参数。

还有这一事实,而不是我的业务逻辑封装成函数,我应该集群这一切都成一个巨大的由一群开关功能分区的情况下?我试着库等redux-actions缓解这个问题,但我仍然无法处理它。我不喜欢还原剂动机我寻找更好的解决方案。

让我们来回顾一下人们选择一些常见的原因useReduceruseState:

  1. 所以业务逻辑可以集中在减速器与分散的组件
  2. 还原剂是纯粹的函数很容易测试隔离的反应
  3. 异径接头允许部分相互依赖的状态被更新(而多useState可能不会)

如果任何这些子弹是混乱的,我推荐你看看这个文章。在本指南中,我将回顾这些物品作为还原剂的三个好处。

第一步:建立一个例子

首先,我要给你一个例子,展示了还原剂的好处我上面提到的,然后我将向您展示如何通过实现相同的功能useState在不牺牲任何的好处useReducer解决方案。

冻计数器

说明的优点/缺点useStatevsuseReducer我要实现一个简单的计数器。计数器可以增加,但也可以冻结。如果在冷冻状态,递增计数器不会做任何事情。

与多个useState的计数器实现
计数器实现useReducer

正如你所看到的,我已经实现了我们的柜台一次以上useState和一次useReducer。然而,StateCounterV1有一些问题。实际上,它甚至没有像预期的那样工作。

我们所期望的,StateCounterV1应该呈现< div > < / div > 1因为我们增加计数器,然后冻结柜台,然后我们再增加。但在现实中呈现2 < div > < / div >因为第二个调用增量没有访问的新值。这说明好处# 3useReduceruseState

这也是明显的StateCounterV1递增计数器,驻留在我们的逻辑组件本身,但在ReducerCounter属于逻辑countReducer(# 1)中获益。

最后我们可以看到,为了测试计数逻辑StateCounterV1我们将会呈现,而测试的逻辑countReducer,我们可以这样做没有呈现一个组件。我们可以测试它通过调用一个国家和一个动作和确保它输出正确的下一个状态(# 2)中获益。

第二步:崩溃的状态

在我们的例子中,我们有一个状态转换,增量,更新但取决于另一个的状态,。在这种情况下,我觉得最好的巩固。理论上我们可以有一个最大的一个useState每个组件和钩仍然实现任何我们想要的功能。但它是完全可以useState多次只要的状态更新时不相互依赖。说完这些,让我们看看巩固国家可以给我们好处# 3的还原剂。

与一个useState计数器实现

现在更新器传递给设置状态在我们的增量函数是自给自足。它不再需要达到的通过闭包来决定如何产生下一个状态。而不是prevState包含所有国家必须执行它的更新逻辑。

因为它是自给自足,我们不再需要声明它在呈现时,我们可以把它的组件。

计数器与解除状态更新

当我们举起state-updater声明以外的组件,我们不仅提高性能,但我们根据变量通过阻止自己不小心关闭像我们一样StateCounterV1。这种模式是本文的有点离题,但无论如何我想提到它。

第三步:提取业务逻辑

在这一点上StateCounterV2仍然是臃肿的计数器逻辑。但是不用担心,所有我们需要做的是将我们所有的柜台业务逻辑提取到一个定制的钩。我们叫它useCounterApi

计数器实现定制的钩

现在StateCounterV3看起来很好。我认为它看起来甚至比ReducerCounter。更不用说这重构是简单的,因为它真的是反逻辑的复制/粘贴到一个定制的钩。但这是事情变得棘手。

有时很难,作为开发人员,确定属于逻辑。我们的大脑是不稳定的,有一些天,它不会发生在我这个逻辑的组件提取到一个自定义计数器钩。这就是为什么我们开发人员需要固执己见的接口来为我们指引正确的方向。

第四步:创建指导

如果我们有描述useCounterApi口头上,我们可能会说,

“这是一个定制的钩,创建并返回一个计数器API”。

在这里是我们的第一个线索。它创建并返回一个API。因此,它是一个API工厂。更具体地说,它是一个计数器API的工厂。

但是我们喜欢抽象的东西,所以下一个问题是,我们如何做一个通用的API工厂吗?好的,让我们把“计数器”部分useCounterApi。现在我们剩下useApi。太棒了,现在我们有通用API工厂。但是我们的业务逻辑去哪里?

让我们更多地思考如何useReducer的工作原理。

const[状态,分派]= useReducer(减速机、initialArg init);

的第一个参数useReducer是一个减速机,第二个参数是初始状态。记住,减速器包含业务逻辑。让我们试着模仿这个接口。

const api = useApi (someApiFactoryFunction initialArg);

好的,感觉我们接近一个解决方案。但是现在我们必须找出到底someApiFactoryFunction是应该做的。

我们知道它应该包含业务逻辑,我们知道它应该知道反应,这样我们可以不用渲染组件测试。我们也知道someApiFactoryFunction不能包含一个useState调用,因为它要注意反应的事情。但它肯定需要状态设置状态。所以我们必须注入状态设置状态其他一些方法。那么我们如何再注入一些功能吗?噢,是的,参数。把这个想法一起锻炼,我们得到以下。

计数器实现useApi

它是。useApi是我们神奇的4行定制钩,揭示了真正的力量useState。API工厂为我们提供当前功能状态和一个设置状态回调,让我们暴露一个API。让我们想想什么样的好处我们只是介绍了这个简单的合同更改。

counterApiFactory不知道反应,这意味着我们现在可以简单地通过测试它吗状态对象和一个设置状态回调(减速机# 2实现受益)。

useApi工厂预计一个API,这意味着我们告诉开发人员他们需要编写API工厂函数签名({状态、设置状态})= > api。这意味着,即使是在我离开的日子里,我的大脑难以认识到一个集群的逻辑可以重构为一个有状态的API,我有一个漂亮的小useApi促使我把我所有的函数有状态业务逻辑放在一个集中的位置。

第五步:优化

目前,useApi不是那么有效。任何组件使用useApi将调用useApi在每个渲染,这意味着apiFactory在每个渲染也会被调用。它没有必要调用apiFactory在每个渲染,而是只有当状态已经改变了。我们可以优化useApi记忆的执行apiFactory

优化useApi (CodeSandbox观)

测试一个API的工厂

现在我们已经实现了useApi钩,让我们看看我们如何测试一个API工厂。

测试counterApiFactory (CodeSandbox观)

这是我们简单创建一个包装器counterApiFactory模仿的行为状态/设置状态。这个helper函数我们可以测试counterApiFactory在一个非常自然的方式。

useApi vs useReducer

现在让我们比较这两个解决方案。

计数器实现useReducer
计数器实现useApi

逻辑封装

在这两种解决方案,逻辑更新状态是集中的,允许简单的推理,调试和测试。然而还原剂只提供一种机制更新状态,他们不提供一种机制检索状态。相反,它的共同编写选择器和下游的减速器应用它们。我们有什么好useApi解决方案是,它不仅封装逻辑更新状态,而且逻辑检索状态。

更新状态

更新状态useReducer,我们需要调度操作。更新状态useApi我们需要调用更新方法。还原剂的潜在优势,在这种情况下,多个还原剂可以听同样的行动。然而,这也有缺点:执行流不是直观的一旦派遣一个动作。如果我需要多个不同的状态更新,我宁愿做明确与多个连续的API方法调用,通过单个派遣行动比播放的还原剂。

性能

还原剂的优点之一是,通过减速器组成,多个还原剂可以听一个派遣行动这意味着你可以有许多的部分在一个渲染状态改变。我还没有想出一个解决方案API工厂组成(虽然肯定有可能)。现在我的解决办法是调用状态更新背靠背在必要时这可能导致比减速器的方式呈现。

样板

Reducer-based解决方案是出了名的boilerplate-y(特别是在处理回来的)。动作类型声明占用额外的空间和调度行为往往是一个更详细的不仅仅是调用一个函数与参数。由于这些理由我认为useApi有一个轻微的边缘useReducer样板代码。

可测试性

还原剂和API工厂很容易测试。

进一步探索useApi

让我们看看我们能做一些很酷的东西useApi

我花时间来实现经典回来的Todo列表的例子通过useApi。这是如何todosApiFactory看起来在useApi实现。

一毛事您可能已经注意到在上面的代码是重复以下样板。

设置状态(prevState = > ({
……prevState,
/ *…* /
});

假设我们的状态是一个对象,因为设置状态不支持浅合并,我们需要这样做以确保我们保持我们不是当前正在处理的任何状态。

我们可以减少一些样板和其他一些很酷的受益于一个图书馆其次是音麦。永远是一个不变性库,允许您编写的代码不变的是可变的。

正如你所看到的,总是帮助我们消除一些烦人的样板代码需要写作时不变的更新。但要小心,永远的便利也是其致命的弱点。开发人员的引入不变性的概念永远不可能完全理解突变的后果。

但是等一下,useApi只提供状态在本地,但Todo列表的例子使用终极版提供全球状态的解决方案。

全球门店API的工厂

让我们看看我们能从API创建全球存储工厂。

不坏,对吧?上下文使全球国家超级简单的反应。现在我们有一个全局状态管理解决方案使用API的工厂。

下面是API工厂工作待办事项列表的例子。

结论

本文把它包起来,包含三个功能,您可能会发现有用的。

这些函数提供有用的局部和全局状态管理由抽象useState

别误会我,还原剂有很多意外的收获,但我只是不能高枕无忧,他们提供的接口。这两个useApiuseReducer复杂的状态管理提供可行的解决方案。这真是一个偏好的问题。

一个有用的结论是,图书馆不需要执行复杂的逻辑是有用的。很多库和框架提供的价值没有与他们执行的逻辑,而是指导他们给开发人员。好库/框架迫使开发人员遵循已知模式通过显式的和固执己见的接口。useApi很少的计算,但鼓励开发人员把他们的有状态业务逻辑在一个集中的位置,所有组件的同时避免污染。

- - -

- - -

得到了媒介的应用betway娱乐官网

一个按钮“App Store下载”说,如果点击它会使你的iOS应用程序商店
说一个按钮上,谷歌玩,如果点击它会使你的谷歌商店
Baidu