I have a code sandbox to demo an issue I am having with Redux and React.
https://codesandbox.io/s/reactredux-3edy8
Basically this reducer does not work:
const initialState = {
byId: {}
};
function addReducer(state = initialState, action) {
switch (action.type) {
case "RECEIVE_DATA":
return {
...state,
byId: {
...state.byId,
[action.payload.id]: [
...state.byId[action.payload.id],
action.payload.data
]
}
};
default:
return state;
}
}
export default addReducer;
here is the action:
import { RECEIVE_DATA } from "./actionTypes";
export function action() {
return {
type: RECEIVE_DATA,
payload: {
id: Math.floor(Math.random() * 2),
data: Math.floor(Math.random() * 10000)
}
};
}
In my own app it throws an error like state.byId[action.payload.id]
is not iterable which is true. But how do I push values to an array that does not yet exist because I do not know the id
?
I thought the issue might be solved by changing the initialState
or perhaps there is a function I am not aware of that allows me to either create an array
or push
to it.
Check if the array exists first. If it does, add a new element. If not, create a new array with one element (the new data from the action)
const initialState = {
byId: {}
};
function addReducer(state = initialState, action) {
switch (action.type) {
case "RECEIVE_DATA":
return {
...state,
byId: {
...state.byId,
[action.payload.id]: (
state.byId[action.payload.id] ? [
...state.byId[action.payload.id],
action.payload.data
] : [action.payload.data])
}
};
default:
return state;
}
}
export default addReducer;
You can read more about ternary statements here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
I am not sure but I think you need something like this
function addReducer(state = initialState, action) {
switch (action.type) {
case "RECEIVE_DATA":
return {
...state,
byId: {
...state.byId,
[action.payload.id]:
[action.payload.data]
}
};
default:
return state;
}
}
The answer to this problem lies in flattening the state. I am sure there are other ways to fix this problem, but I found this the cleanest.
Typically the byId
property of state is created through flattening state per the guidelines in the docs
I take it one step further, making the byId
property an Array instead of an Object. I move the id
into the objects of the array like in this new sandbox: https://codesandbox.io/s/reactredux-zj1n4
I just have to remember the byId
is now an array when I map the state to my components.
No functionality is lost and my byId
field can now support multiple different ids if needed (eg if I had many to many relationships on the objects)
Here is the code:
in reducer
case "RECEIVE_DATA":
return {
...state,
byId: [...state.byId, action.payload.data]
};
new action:
export function action() {
return {
type: RECEIVE_DATA,
payload: {
data: {
id: Math.floor(Math.random() * 2),
value: Math.floor(Math.random() * 10000)
}
}
};
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.