React Redux:reducer应该包含任何逻辑吗

pkmbmrz7  于 2023-08-05  发布在  React
关注(0)|答案(4)|浏览(94)

我有一个购物车减少功能添加,更新和删除的情况下。我在redux商店中也有一个产品阵列。当有两个项目添加到product数组中时,我增加了数量值,而不是两个项目。我的主要问题是,reducer是否应该包括任何逻辑,即确定products数组是否已经包含确切的产品,并且仅返回产品数量的更新,或者是否应该在检查现有产品并添加新产品或更新数量的表示组件内处理此行为?

function CartReducer (state = initialState, action) {
  switch (action.type) {
    case AddToCart:
      return {
        ...state,
        products: [...state.products, action.product],
        totalPrice: state.totalPrice += (action.price * action.quantity)
      }

    case RemoveItemCart:

      return {
        ...state,
        products: [
          ...state.products.slice(0, action.index),
          ...state.products.slice(action.index + 1)
        ]
      }

    case UpdateItemQuantity:
      return {
        ...state,
        products: state.products.map((product, index) => {
          if (index === action.index) {
            return Object.assign({}, product, {
              quantity: action.quantity
            })
          }
          return product
        })
      }

    default:
      return state
  }
}

字符串

byqmnocz

byqmnocz1#

根据Redux FAQ中关于reducer和action creators之间的分割逻辑的条目:
对于在reducer或action creator中应该使用哪些逻辑,没有一个明确的答案。一些开发人员更喜欢使用“胖”的动作创建器,使用“瘦”的还原器,简单地获取动作中的数据并盲目地将其合并到相应的状态中。其他人试图强调保持动作尽可能小,并最大限度地减少动作创建器中getState()的使用。(对于这个问题,其他异步方法,如Sagas和Observables属于“动作创建者”类别。
将更多的逻辑放入还原器中有一些潜在的好处。动作类型可能会更语义化和更有意义(比如“USER_UPDATED”而不是“SET_STATE”)。此外,在reducer中有更多的逻辑意味着更多的功能将受到时间旅行调试的影响。
这句话很好地总结了这种二分法:
现在,问题是在动作创建器中放置什么,在缩减器中放置什么,在胖动作对象和瘦动作对象之间进行选择。如果您将所有逻辑都放在操作创建器中,那么最终将得到一个庞大的操作对象,这些对象基本上声明了状态的更新。Reducers变得纯粹,愚蠢,添加这个,删除那个,更新这些功能。他们将很容易组成。但你的商业逻辑不会在那里。如果你在reducer中放入更多的逻辑,你最终会得到一个漂亮的、瘦的动作对象,大部分数据逻辑都在一个地方,但是你的reducer很难组合,因为你可能需要来自其他分支的信息。你最终会得到一个大的缩减器或一个从州里更高的地方得到额外参数的缩减器。
我也写了自己对“厚和薄”减速器的想法:
在动作创建器中放置更多逻辑与在还原器中放置更多逻辑之间存在有效的权衡。我最近看到的一个好观点是,如果你在reducer中有更多的逻辑,这意味着如果你在进行时间旅行调试(这通常是一件好事),就可以重新运行更多的东西。
我个人倾向于同时把逻辑放在这两个地方。我编写的操作创建器需要时间来确定是否应该分派操作,如果应该分派,则内容应该是什么。但是,我也经常编写相应的reducer,它们查看操作的内容,并执行一些复杂的状态更新作为响应。

更新

从2020年开始,我们特别建议将尽可能多的逻辑放在减速器中
只要有可能,尽量把计算新状态的逻辑放到适当的reducer中,而不是放在准备和分派动作的代码中(比如点击处理程序)。这有助于确保更多的实际应用逻辑易于测试,使时间旅行调试更有效地使用,并有助于避免可能导致突变和bug的常见错误。
在一些有效的情况下,应该首先计算一些或所有新状态(例如生成唯一的ID),但这应该保持在最低限度。

lxkprmvk

lxkprmvk2#

当然!Reducer应该是纯函数,所以逻辑也必须是纯函数。这意味着应该有零副作用。副作用包括(但不限于):

  • 数据库请求/存储
  • 文件IO
  • REST/async调用
  • 全局或外部突变
  • 任何类型的数据变化

所以reducer不应该改变进入的状态,而是返回一个只对副本进行修改的副本。不可变的值(如字符串、数字、未定义等)可以按原样返回,如果没有修改,状态也可以。但是,如果您需要对任何输入进行任何更改,则需要返回一个新副本或新值。
关于从reducer调用的逻辑,只要所有代码满足这些要求,那么您就符合Redux模式。
不幸的是,JavaScript没有办法确定任何给定的代码何时有副作用(其他语言有),所以你应该只知道你在调用什么。
如果你失败了,它会破坏Redux吗?不,但事情可能不会完全按照您(或Flux/Redux开发人员)的期望工作。

bogh5gae

bogh5gae3#

不应该包含逻辑(我的推理)

编辑:许多年后,我仍然将动作视为可以以某种方式声明依赖关系、操作和返回的时间段或线程。我觉得reducer是一个通用词,但通常与某些东西的路由和子路由有关,通常是一条消息或一个动作。在react/redux中,我认为它代表了商店的形状,这是一种从大型action对象中提取相关值的好方法。在non-react/redux中,你可以通过多种方式更新状态,例如。使用return、setters、模块全局变量的变化等
在redux中,我只是觉得reducer比任何东西都更能代表你的商店,而action/object既是消息也是处理程序;实际上是序列化的函数名和参数,您可以提供这些参数来使用调用它。确定要运行的下一个操作并直接传递其参数被认为是编排,而不是更集中于全局/非消息状态的编排。我认为thunks是声明性链+编排,其中sagas将更加集中编排,尽管您可以通过异步(然后vs await)来产生编排,指定延续函数(成功或错误),在继续之前验证消息中的transactionId/runNumber/threadId是否匹配全局状态。我认为这是分布式系统设计中的常见做法。
我还发现,在同步环境中,你需要一个动作来处理异步成功/错误的每一个延续,你应该在主线程/承诺队列循环中捕获错误:

queue = queue
  .then(() => {
    state = onAction(action, state);
  })
  .catch();

字符串
如果你真的想组织这些东西,去异步,使用const 100%的时间,否则创建一个函数,并把每一个轻微的格式缺陷(缩进)变成一个命名良好的,自我提升的函数。

魔鬼代言人

Array.prototype.reduce肯定接受一个名为reducer的处理程序,并且肯定有逻辑,但我认为reducer只是一个流行的通用词,指的是路由,在这种情况下路由状态而不是动作(onAction)。没有行动,或者更确切地说,行动就是还原本身。

原创帖子

在普通redux中(没有sagas/thunks),action收集并发出大对象,reducer将其拆分到适当的位置。你真的应该把注意力集中在行动上而不是减少者上
您可以在操作创建器中的每一步按程序分派操作,而不是大对象,这似乎是最佳答案所提倡的(但对于普通redux来说是不可能的)

*组件:将现有的redux数据传递到动作中
*操作:收集数据并发出大对象,适用于尽可能多的Reducer
*减速器:提取操作对象,以实现粒度、非重复、平面存储(与整体、冗余、嵌套文件夹相反)。我推荐显式的initialState,以便于维护和明显的数据形状(状态永远不应该改变形状;如果连接的对象不可用,则按id序列化,而不是有时嵌套完整对象)。

id可以被认为是一个序列化的内存引用或“指针”,它可以有不同的内容,但可以是===本身; id是对象引用。序列化。

    • 副作用:**后续动作监听器/调度器,当你不想在发出初始事件之前等待时很有用(sagas是基于订阅的,thunks是声明式链)
      经验法则是尽可能热切地做每件事

早期操作(早期返回、快速失败、提升状态等)澄清了特定的依赖项是否并发存在,并使决策变得容易
急切的操作福尔斯“关注点分离”和模块化、声明性、有状态、实用、易读的代码的简单主题:声明依赖,操作,返回
其他一切都是一个排序问题,应该尽可能急切地去做
减速器是你最不想“做”任何事情的地方。它实际上是一个“返回”,应该简单地从操作对象中选择数据

368yc8dk

368yc8dk4#

考虑一下你可能想在你的中间件中做什么……如果你把所有的逻辑都放在你的reducer中,那么中间件中的记录将不会有业务逻辑应用到它。

  1. dispatch(new UpdatePerson(person))
    1.运行中间件并拦截UpdatePerson操作
  2. reducer -更新人员的年龄值
    如果你想说,把你的记录保存在一个存储中,那么reducer逻辑将运行得太晚,你将不能访问中间件中你需要的状态下的改变的记录。

相关问题