React Redux:Reducer是否包含任何逻辑

IVI*_*IVI 13 reactjs react-native redux react-redux

我有一个推车减速机功能,添加,更新和删除案例.我还在redux商店中有一个产品阵列.如果有两个项目添加到产品数组中,而不是有两个项目,我会增加数量值.我的主要问题是,如果减速器包含任何逻辑,即确定产品阵列是否已包含确切的产品,并且只返回产品数量的更新,或者是否应在演示组件内检查现有产品并添加新产品产品或更新数量?

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
  }
}
Run Code Online (Sandbox Code Playgroud)

mar*_*son 19

根据Redux FAQ条目,在reducers和action creators之间拆分逻辑:

对于减速器或动作创建者应该采用什么样的逻辑,没有一个明确的答案.一些开发人员更喜欢拥有"胖"动作创建器,其中"瘦"缩减器只是简单地将动作中的数据接收并盲目地将其合并到相应的状态中.其他人试图强调保持尽可能小的动作,并最小化动作创建者中getState()的使用.(出于这个问题的目的,其他异步方法,如sagas和observables属于"行动创造者"类别.)

将更多逻辑放入减速机有一些潜在的好处.动作类型可能更具语义性和更有意义(例如"USER_UPDATED"而不是"SET_STATE").此外,在reducer中使用更多逻辑意味着更多功能将受到时间旅行调试的影响.

这个评论很好地总结了二分法:

现在,问题是在动作创建器中放置什么以及在reducer中放置什么,在fat和thin动作对象之间进行选择.如果将所有逻辑放在动作创建器中,最终会生成基本上声明状态更新的胖动作对象.Reducers变得纯粹,愚蠢,添加 - 删除它,更新这些功能.它们很容易构成.但是你的业务逻辑并不多.如果你在reducer中加入了更多的逻辑,你最终会得到漂亮的瘦动作对象,大部分数据逻辑都集中在一个地方,但是你的reducer更难以编写,因为你可能需要来自其他分支的信息.你最终得到了大型减速器或减速器,它们从该州的较高位置获取额外的参数.

我还写了自己关于"厚薄"减速器的想法:

在行动创造者中加入更多逻辑与在减速器中加入更多逻辑之间存在有效的权衡.我最近看到的一个好处是,如果你在减速器中有更多的逻辑,这意味着如果你是时间旅行调试(这通常是一件好事),可以重新运行更多的东西.

我个人倾向于在两个地方同时使用逻辑.我写动作创建者需要花时间来确定是否应该分派动作,如果是,那么内容应该是什么.但是,我还经常编写相应的reducers来查看操作的内容并执行一些复杂的状态更新作为响应.


Bri*_*sio 10

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

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

因此,reducers 永远不应该改变进入的状态,而是返回一个仅对副本进行修改的副本,如果是这样的话。不可变值(如字符串、数字、未定义等)可以按原样返回,如果尚未修改,则可以声明。但是,如果您需要对任何输入进行任何更改,您将返回一个新副本或一个新值。

关于从您的减速器调用的逻辑,只要所有代码都满足这些要求,那么您就符合 Redux 模式。

不幸的是,JavaScript 没有办法确定任何给定的代码何时有副作用(其他语言有),所以你应该只知道你在调用什么。

如果失败,它会破坏 Redux 吗?不会。但事情可能不会像您(或 Flux/Redux 开发人员)所期望的那样工作。


nea*_*sic 7

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

\n

编辑:很多年后,当您可以以某种方式声明依赖项、操作和返回时,我仍然将操作视为时间段或线程。我觉得reducer是一个通用词,但通常与某些东西的路由和子路由相关,通常是消息或操作。在react/redux中,我认为它代表了商店的形状,这只是从大型操作对象中提取相关值的好方法。在非 React/Redux 中,您可以通过多种方式更新状态,例如。具有返回、设置器、模块全局变量等的突变

\n

在redux中,我只是觉得reducer比任何东西都更能代表你的store,而action/object既是消息又是处理程序;实际上,您可以提供序列化函数名称和参数来调用它。确定要运行的下一个操作并直接传递其参数被视为编排,而不是更以全局/非消息状态为中心的编排。我认为 thunk 是声明性链+编排,其中 sagas 将更加集中地编排,尽管您可以通过异步(然后与等待)、指定验证 transactionId/runNumber/threadId 的延续函数(成功或错误)来进行编排。在继续之前,消息与全局状态匹配。我认为这是分布式系统设计中的常见做法。

\n
\n

我还发现,在同步环境中,您需要一个操作来处​​理异步成功/错误情况的每个延续,并且您应该在主线程/承诺队列循环中捕获错误:

\n
queue = queue\n  .then(() => {\n    state = onAction(action, state);\n  })\n  .catch();\n
Run Code Online (Sandbox Code Playgroud)\n

如果你真的想组织这些东西,那就采用异步,使用const100% 的时间创建一个函数,并将每个小的格式缺陷(缩进)变成一个名称良好的自提升函数。

\n

魔鬼代言人

\n

Array.prototype.reduce肯定接受一个名为 a 的处理程序reducer,并且肯定有逻辑,但我认为 reducer 只是一个流行的通用词,指的是路由,在本例中是路由状态而不是操作 ( onAction)。没有任何行动,或者更确切地说,行动就是减少本身。

\n

原帖

\n

在普通的 redux 中(没有 sagas/thunk),actions 会收集并发出大型对象,reducer 会将这些对象分割到适当的位置。你应该真正关注行动而不是减速器

\n

您可以在动作创建器中的每一步按程序分派动作,而不是大型对象,这就是最佳答案似乎所提倡的(但对于普通的 redux 是不可能的

\n
\n
    \n
  • 组件:将现有的 redux 数据传递到操作中

    \n
  • \n
  • Actions:收集数据并发出大对象,适用于尽可能多的减速器

    \n
  • \n
  • 缩减器:提取操作对象以进行粒度、非重复、扁平存储(而不是整体、冗余、嵌套文件夹)。我建议使用显式,initialState以便于维护和明显明显的数据形状(状态永远不应该改变形状;如果连接的对象不可用,则序列化id而不是有时嵌套完整对象)。

    \n

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

    \n
  • \n
  • *副作用:后续操作侦听器/调度程序,当您不想在发出初始事件之前等待时很有用(saga 是基于订阅的,thunk 是声明性链)

    \n
  • \n
\n
\n

经验法则是尽可能热切地做每件事

\n

热切操作(早期返回、快速失败、提升状态等)可以明确是否同时存在特定的依赖关系,并可以轻松做出决策

\n

Eager 操作符合 \xe2\x80\x9c 关注点分离 \xe2\x80\x9d 和模块化、声明性、有状态、务实、易读代码的简单主题:声明依赖项、操作和返回

\n

其他一切都是顺序问题,应该尽快完成

\n

减速器是您\xe2\x80\x99d 最不想做\xe2\x80\x9c 做\xe2\x80\x9d 任何事情的地方。它\xe2\x80\x99s实际上是\xe2\x80\x9creturn\xe2\x80\x9d并且应该简单地从操作对象中选择数据

\n