Why we should prefer immutability in Redux - reactjs

I am new to Redux and was learning how to work with it and trying to get how it works behind the scenes. But, I faced the confusion with why we need to keep state immutable in Redux, I admit, there has already been asked a question close to mine Why should objects in Redux be immutable? but in there I couldn't find clear explanation on why we need to keep state immutable. For example, I have this code which mutates the state on button click and the below code works pretty fine even if I mutate state:
const initialState = {
counter: 0
};
const reducer = (state = initialState, action) => {
if (action.type === "INCREMENT") {
return {
counter: state.counter + 1
};
}
return state;
};
export default reducer;
Please can you kindly explain why above code works fine even if I mutate state and why I need to make state immutable.

Related

How to access root state in a reducer in redux toolkit?

I have a simple counter slice. In increment function I want to access root state. How can I do that?
const initialState = {
value: 1
}
export const counterSlice = createSlice({
name: "counter",
initialState,
reducers: {
increment: (state) => {
state.value++
}
}
})
Generally, you can't. Redux (and not only toolkit) is designed around the idea that your Reducer should only rely on it's own state value and the contents of the action coming in, nothing else.
If you really really need data from another state slice, you probably need to copy that into the action when calling it, but it is usually considered a bad idea.
You might have chosen your slice too small.

Is this correct way to deep clone array of objects as property inside object?

I have this reducer.
const userInitialState = {
users: [],
};
const users = (state = userInitialState, action) => {
if (action.type === "FETCH_USERS") {
return {
...state,
users: action.payload,
};
}
return state;
};
export default combineReducers({
users,
});
initially the users property is edmpty array,when the new results from the api call comes
for example response like
https://jsonplaceholder.typicode.com/users
is this the correct way for immutable way in redux store for my array inside ?
A proper immutable update is best described as "a nested shallow clone". You don't want to copy every value in a nested data structure - just the ones that need to be updated.
But yes, that looks correct.
A couple additional observations:
You should read through the post The Complete Guide to Immutability in React and Redux and the Redux docs page on Immutable Update Patterns to better understand how to do immutable updates correctly
But, you should really be using our official Redux Toolkit package, which uses Immer to let you write "mutating" update logic that is turned into safe and correct immutable updates.

Where should I put a common code in Redux?

I have an application with Reactjs and Redux. There is an action which resets the state of the reducers. My question is: where is the best place to perform that? I am considering two options:
each reducer handle the action and resets its state
const reducer1 = (state = defaultState, action) => {
switch (action.type) {
case 'reset': {
// ...
}
// ...
}
the root reducer resets the global state
const appReducer = combineReducers({
reducer1,
reducer2,
reducer3
})
const rootReducer = (state, action) => {
if ( (action.type === 'reset') ) {
state = {}
}
return appReducer(state, action)
}
The best practice is to have an action for reseting each reducer, this helps for extensibility in the future. Dispatch the clearState action, but do not set an empty object. Set it to the initial state, because if you put an empty object you can introduce bugs
The first thing we must have clear is that reducers don't have states, stores have states, so you shouldn't say "the state of the reducer".
A reducer is a function that performs some change in the state of a store, and there is no specific limitation in the scope of such change, besides the scope of the store, so many reducers have overlapping scopes over the state of the store.
After that, I see no reason why you can not reset the whole state of the store with a single reducer, and when you need to make other changes with different scope, you can create other reducers to manage it.

React redux-strange behavior, prevState and newState change together

I started to work on some frontend project, I needed to plant foundation and I choosed to go with react and redux. I went through some tutorials and started to build my project.
Everything was working fine, but all of sudden I m stuck with problem I'm not even sure how to describe it.
Problem is connected with using redux, reducers.
In short somehow my prevState was changing with the newState. The worst part is I cant share much more information, I'm new to this react/redux, so I'm not even sure if this is even possible.
Here is the example code:
export default function (state: UserReducerState = initialState, action: Action): any {
const newState = Object.assign({}, state);
console.log(state);
state.loginStatus.username="This change should only be on prevState";
console.log("newState",newState);
return newState;
};
When I console.log(newState) it has the change from the old state even though the newState was copied before the state.loginStatus.username ="This change......."
I dont know what code should I show more, but this is where problem start,I think.
How is even possible that object that is copied have the refrence to the old one ?
Issue
Even though you are copying the state object it isn't a deep copy. You are mutating the more deeply nested properties of your previous state object since the new state is simply holding a reference to them.
state.loginStatus.username = "This change should only be on prevState";
newState is a new object, but newState.loginStatus.username is reference back to the same object the previous state holds.
Solution
I'm not sure why you'd mutate your old state object in a reducer, but when updating the more deeply nested properties in the new state you must shallow copy any nested state that is being updated. Typically this is achieved via the spread syntax.
export default function (state: UserReducerState = initialState, action: Action): any {
const newState = {
...state,
loginStatus: {
...state.loginStatus,
username: "This change should only be on newState".
},
};
console.log(state);
console.log("newState", newState);
return newState;
};

Update state in deep structure not re-rendering component

I just got started with React+Redux and I have a problem.
I know that I am never supposed to alter the old state in the reducer and I am not doing that.
However, when I change a variable like this in my reducer, my component is not re-rendering, even though I have mapStateToProps with state.coupons
// this deep copies everything
let newState = Object.assign({}, state);
newState.coupons[2].events[0].eventRows[0].alternatives[0].selected = true;
return newState;
What am I doing wrong?
EDIT:
I even tested to use newState = JSON.stringify(JSON.parse(oldState)) but with no success
EDIT:
This is my mapStateToProps function
const mapStateToProps = (state, ownProps) => ({
coupons: state.coupons,
currentDraw: state.currentDraw
});
You can find the solution in redux docs: http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html#updating-nested-objects
The key to updating nested data is that every level of nesting must be
copied and updated appropriately. This is often a difficult concept
for those learning Redux, and there are some specific problems that
frequently occur when trying to update nested objects. These lead to
accidental direct mutation, and should be avoided.
You can do this manually, something like:
function updateVeryNestedField(state, action) {
return {
....state,
first : {
...state.first,
second : {
...state.first.second,
[action.someId] : {
...state.first.second[action.someId],
fourth : action.someValue
}
}
}
}
}
In practice, it's better to use a helper library to do this. You can find a list of helper libraries at https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md#immutable-update-utilities, I would personally recommend immutability-helper or just switching to immutable.js.

Resources