I'm struggling to understand Redux and am loosing a local state upon hitting a button on a React page. The situation is as follows:
Suppose you are on a React page, which has a local state:
{"player": "PersonA"}
There's also a button on the same React page. Pushing the button triggers a Redux action. The associated controller method returns:
return res.status(200).json({
statusCode: 200,
success: true,
payment: {"amount": "3", "currency": "EUR"},
});
And the reducer:
case APPLY_SUCCESS:
console.log(...state); // returns undefined
return { ...state, paymentData: action.payload.payment };
After hitting the button on the React page, the local state only contains paymentData
. So player
is gone from the local state. I thought ...state
in the reducer should ensure maintaining the existing local state that is unaffected by the action. So it would just append paymentData
to the local state and also keep player
.
My question:
- Am I correct that
...state
in the reducer is supposed to ensure that the local state that is unaffected by the action, remains part of the local state? - If so, what could be the reason
...state
is undefined? How can I ensureplayer
is still part of the local state?
CodePudding user response:
console.log(...state)
might throw a type error, because spreading is usually done inside arrays and object.
However the second part where you return {...state, paymentData: data}
should work as you expect, with only paymentData being changed from state, since {...state}
is simply making a shallow copy of the state object (not deep), and then replacing the paymentData key in this copy.
If you are working with a deeply nested key, I would look into lodash's deepClone function to create a deep copy of the state, and not a shallow copy, to prevent writing directly to redux state (and creating unexpected bugs)
Recommendation:
Check if console.log(state)
is undefined or is an empty object.
If that's the case, state is not being passed into the reducer, or initialized properly, and you should check how it's being passed in.
Ensure that the reducer is following this model to initialize it properly. This is taken from redux's own docs and you can look at more examples there.
const initialState = {
todos: [
{ id: 0, text: 'Learn React', completed: true },
{ id: 1, text: 'Learn Redux', completed: false, color: 'purple' },
{ id: 2, text: 'Build something fun!', completed: false, color: 'blue' }
],
filters: {
status: 'All',
colors: []
}
}
// Use the initialState as a default value
export default function appReducer(state = initialState, action) {
// The reducer normally looks at the action type field to decide what happens
switch (action.type) {
// Do something here based on the different types of actions
default:
// If this reducer doesn't recognize the action type, or doesn't
// care about this specific action, return the existing state unchanged
return state
}
}