Do events (DOM events or system events) have a 1:1 relationship with actions? i.e. should a single click event trigger only one action?
For example, let's say we have a page which displays a table of 10 rows and 2 columns. Each row has a Product field and an Amount field. The Amount field has a range input with a range of [0, 10]. The user can set the Amount of each Product individually.
The user is also given 2 options, through the use of 2 buttons.
- Pressing the second button will disable all but the first product in the table (effectively setting their Amount to 0 and the user can no longer interact with them to set their Amount). Let's call this
Option B - Pressing the first button enables all Products after the first (by default setting their Amount to 1 for each of them) and the user can once again interact with them, to set their amounts individually. Let's call this
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
`````````
The state of this 'app' is described by this simple object
state = {
option : <String>,
products : [
{
name : <String>,
amount : <Integer>
}, ...
]
}
We also have these 4 simple action creators:
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 }
}
}
For the sake of simplicity, we have only one reducer.
In this example, selecting Option B should have the following effects on the state :
- Change
optiontoB - Set the amount of every
productafter the first to0
Selecting Option A should have the following effects on the state, respectively :
- Change
optiontoA - Set the amount of every
productafter the first to1
Incrementing the amount of Product A should have the following effects on the state :
- Increment the amount of Product A by 1
What would be the proper way to implement these changes?
a) Have the onClick handler of the option buttons do the following:
- Fire a
store.dispatch(setOption(option)) - For each product after the first one fire a
store.dispatch(setAmount(productName, amount))(amount= 1 for option A, 0 for option B)
b) Have the onClick handler of the option buttons do the following:
Fire a
store.dispatch(setOption(option))And have the reducer change the
optionas well as theamountof every product after the first one to the specified amount (amount= 1 for option A, 0 for option B)
If we go with a) each case in the switch (action) {} statement of the reducer deals with just one aspect of the state, but we have to fire more than one action from one click event
If we go with b) we fire only one action from the click event but the case for SET_OPTION in the reducer not only changes the option but also the amount of products.