Подтвердить что ты не робот

Имеют ли события и действия отношения 1:1 в Redux?

У событий (событий DOM или системных событий) есть отношения 1:1 с действиями? т.е. если одно событие щелчка запускает только одно действие?

Например, скажем, у нас есть страница, которая отображает таблицу из 10 строк и 2 столбца. Каждая строка имеет поле "Продукт" и поле "Сумма". Поле "Сумма" имеет вход диапазона с диапазоном [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
 `````````


Состояние этого "приложения" описывается этим простым объектом

state = {
    option : <String>,
    products : [
        {
            name : <String>,
            amount : <Integer>
        }, ...
    ]
}

У нас также есть эти 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 }
    }
}

Для простоты мы имеем только один редуктор.

В этом примере выбор Option B должен иметь следующие эффекты для состояния:

  • Измените option на B
  • Задайте количество каждого product после первого значения 0

Выбор Option A должен иметь следующие эффекты для состояния, соответственно:

  • Измените option на A
  • Задайте количество всех product после первого значения 1

Приращение количества продукта A должно иметь следующие эффекты для состояния:

  • Увеличьте количество продукта A на 1

Каким будет правильный способ реализовать эти изменения?

a) Попросите обработчик onClick кнопок option выполнить следующие действия:

  • Пожар a store.dispatch(setOption(option))
  • Для каждого продукта после первого пожара a store.dispatch(setAmount(productName, amount)) (amount= 1 для опции A, 0 для опции B)

b). Обработчик onClick кнопок option выполняет следующие действия:

  • Пожар a store.dispatch(setOption(option))

    И замените редуктор на option, а также amount каждого продукта после первого на указанное количество (amount= 1 для опции A, 0 для опции B)

Если мы идем с a), каждый случай в выражении switch (action) {} редуктора имеет дело только с одним аспектом состояния, но мы должны запускать более одного действия из одного click событие

Если мы идем с b), мы запускаем только одно действие из события click, но случай для SET_OPTION в редукторе не только изменяет option, но также и amount продуктов.

4b9b3361

Ответ 1

Нет общего ответа на этот вопрос, поэтому мы должны оценивать каждый случай.

При использовании Redux вы должны стремиться поддерживать баланс между сохранением простых редукторов и значимым ведением журнала действий. Лучше всего, когда вы можете прочитать журнал действий, и имеет смысл, почему все произошло. Это аспект "предсказуемости", который предлагает Redux.

Когда вы отправляете одно действие и изменяете его в разных частях, легко понять, почему они меняются позже. Если вы отлаживаете проблему, вы не будете поражены количеством действий, и каждая мутация может быть прослежена до того, что сделал пользователь.

По контрасту, когда вы отправляете несколько действий в ответ на одно взаимодействие с пользователем, сложнее сказать, почему они были отправлены. Они загромождают журнал действий, и если есть ошибка в том, как они были отправлены, журнал не обнаруживает основополагающих причин.

Хорошим правилом является то, что вы никогда не хотите dispatch в цикле. Это крайне неэффективно и, как отмечено выше, скрывает истинную природу того, почему произошло изменение. В вашем конкретном примере я бы рекомендовал запустить одно действие.

Однако это не означает, что стрельба одним действием всегда является способом выхода. Как и все, это компромисс. Существуют допустимые случаи, когда более удобно запускать несколько действий в ответ на одно взаимодействие пользователя.

Например, если ваше приложение позволяет пользователям тегировать продукты, удобнее будет отделять действия CREATE_TAG и ADD_TAG_TO_PRODUCT, потому что, хотя в этом случае они происходят одновременно, они могут также произойти отдельно, и это может проще писать редукторы, которые обрабатывают их как разные действия. Пока вы не злоупотребляете этим шаблоном и не делаете что-то подобное в цикле, вы должны быть в порядке.

Храните журнал действий как можно ближе к истории взаимодействия с пользователем. Однако, если это затрудняет реализацию редукторов, рассмотрим разделение некоторых действий на несколько, если обновление пользовательского интерфейса можно рассматривать как две отдельные операции, которые просто происходят вместе. Не попадайте ни в одну из крайностей. Предпочитайте чистоту редуктора до идеального логарифма, но также предпочитайте не отправлять в петлю до ясности редуктора.

Ответ 2

Чтобы добавить к Dan отличный ответ, когда вы идете по b), вы все равно можете обрабатывать отдельные части состояния, как вы сказали в a), путем расщепление корневого редуктора на более мелкие, например Redux docs показать. Вы должны разделить обработку состояния, составив редукторы, а не произвольно отправляя другие действия. Как сказал Дэн, он помогает в действиях, объясняющих, почему.