事件和操作在Redux中是否具有1:1的关系?

Dim*_*nis 32 javascript events action redux

事件(DOM事件或系统事件)与操作有1:1的关系吗?即单击事件应该只触发一个动作?

例如,假设我们有一个显示10行2列表的页面.每行都有一个Product字段和Amount字段.Amount字段的范围输入范围为[0,10].用户可以单独设置每个产品的数量.

通过使用2个按钮,用户还可以选择2个选项.

  • 按第二个按钮将禁用表格中除第一个产品外的所有产品(有效地将其金额设置为0,用户无法再与它们交互以设置其金额).我们称之为Option B
  • 按第一个按钮可在第一个按钮之后启用所有产品(默认情况下,将每个产品的金额设置为1),用户可以再次与它们进行交互,以单独设置其金额.我们称之为Option A.

Option A selected:

    | PRODUCT          | AMOUNT    |
    |------------------|-----------|
    | Product A        |   - 4 +   |
    | Product B        |   - 0 +   |
    | Product C        |   - 4 +   |
    ````````````````````````````````

 _________
| Option A|  OPTION B
 `````````

Option B selected:

    | PRODUCT          | AMOUNT    |
    |------------------|-----------|
    | Product A        |   - 4 +   |
    | Product B        |  Disabled | (Amount == 0)
    | Product C        |  Disabled | (Amount == 0)
    ````````````````````````````````

          _________
OPTION A | OPTION B|
          `````````

Option A selected again:

    | PRODUCT          | AMOUNT    |
    |------------------|-----------|
    | Product A        |   - 4 +   |
    | Product B        |   - 1 +   |
    | Product C        |   - 1 +   |
    ````````````````````````````````

 _________
| Option A|  OPTION B
 `````````


这个'app'的状态由这个简单的对象描述

state = {
    option : <String>,
    products : [
        {
            name : <String>,
            amount : <Integer>
        }, ...
    ]
}
Run Code Online (Sandbox Code Playgroud)

我们还有这4个简单的动作创建者:

function setOption(option) {
    return { type : 'SET_OPTION', option : option};
}

function incAmount(productName) {
    return {
        type : 'INCREMENT_AMOUNT',
        product : productName
    }
} 

function decAmount(productName) {
    return {
        type : 'DECREMENT_AMOUNT',
        product : productName
    }
}

function setAmount(productName, amount) {
    return {
        type : 'SET_AMOUNT',
        payload : { product : productName, amount : amount }
    }
}
Run Code Online (Sandbox Code Playgroud)

为简单起见,我们只有一个减速器.

在此示例中,选择Option B应对状态具有以下影响:

  • 更改optionB
  • 设置第一个product之后的每个数量0

选择Option A应分别对状态产生以下影响:

  • 更改optionA
  • 设置第一个product之后的每个数量1

增加产品A的数量应对状态产生以下影响:

  • 将产品A的数量增加1

实施这些变化的正确方法是什么?

a)onClickoption按钮的处理程序执行以下操作:

  • 火a store.dispatch(setOption(option))
  • 对于每个产品在第一个产品之后触发a store.dispatch(setAmount(productName, amount))(amount对于选项A = 1,对于选项B为0)

b)onClickoption按钮的处理程序执行以下操作:

  • 火a store.dispatch(setOption(option))

    并且将减速器optionamount第一个之后的每个产品的更改更改为指定的量(amount对于选项A = 1,对于选项B为0)

如果我们考虑a)switch (action) {}减速器声明中的每个案例只处理一个州的一个方面,但我们必须从一个click事件中触发多个动作

如果我们选择b)我们只从click事件中触发一个动作,但SET_OPTION减速器中的情况不仅会改变产品option而且会改变amount产品.

Dan*_*mov 42

这个问题没有一般性答案,所以我们必须根据具体情况进行评估.

使用Redux时,您应该努力在简化Reducer和保持action log有意义之间保持平衡.最好是你可以阅读行动日志,这是事情发生的原因.这是Redux带来的"可预测性"方面.

当您调度单个操作,并且状态的不同部分响应时,很容易告诉他们为什么稍后更改.如果您调试问题,您不会被操作量所淹没,并且每个突变都可以追溯到用户所做的事情.

通过constrast,当您在响应单个用户的交互派遣多个动作,这是很难说为什么他们被分派.它们使操作日志变得混乱,如果调度它们的方式有误,则日志不会发现根本原因.

一个好的经验法则是你永远不想dispatch循环.这是非常低效的,正如上面提到的,掩盖的真正性质,为什么变化发生了.在您的特定示例中,我建议触发一个动作.

然而,这并不意味着发射单一动作始终是要走的路.像所有事情一样,这是一种权衡.在有效的情况下,响应单个用户交互来触发多个动作更方便.

例如,如果您的应用程序允许用户标记产品,则分离CREATE_TAGADD_TAG_TO_PRODUCT操作可能更方便,因为虽然在这种情况下它们同时发生,但它们也可能单独发生,并且可以更容易地编写将其处理为不同的行动.只要你不滥用这种模式并且不在循环中做这样的事情,你应该没事.

保持操作日志尽可能接近用户交互历史记录.但是,如果它使得reducers实现变得棘手,可以考虑将一些动作拆分成几个,如果UI更新可以被认为是恰好在一起的两个单独的操作.不要陷入任何一个极端.将减速机的清晰度提高到完美的日志,但也不希望在循环中调度到减速器的清晰度.