Daniel Daniel - 4 months ago 13
Javascript Question

Redux state changes but shouldn't

I have a problem. I have a simple Grid and the Grid gets its data from the redux state. But when I sort, I noticed that my data changes in the state, which it shouldn't or I missunderstood redux at this point.
Here a bit of code

reducer:

const gridOptions = {
columns: ["id", "name", "lastname"],
data: [
{id: 1, name: "test", lastname: "test2"},
{id: 2, name: "test1", lastname: "test3"}
],
sortBy: {},
filter: {}
}

const rootReducer = combineReducers({
data: function (state = gridOptions.data, action) {
return [...state];
},
selectedRow: function (state = {}, action) {
switch (action.type) {
case "ROW_SELECTED":
return action.data
default:
return state
}
},
sortBy: function (state = gridOptions.sortBy, action) {
switch (action.type) {
case "SORT_CHANGE":
return Object.assign({}, action.column);
default:
return state;
}
},
columns: function (state = gridOptions.columns, action) {
return state;
},
filter: function (state = gridOptions.filter, action) {
return state;
}
})

const store = createStore(rootReducer);


the container component. I know it is a bit messy.

var mapStateToProps = (state) => {
return {
data: (() => {
if (!state.sortBy) {
return state.data
} else {
return state.data.sort()
}
})(),
selectedRow: state.selectedRow,
sortBy: state.sortBy
}
}

var mapDispatchToProps = (dispatch) => {
return {
onRowSelected: data => dispatch({type: "ROW_SELECTED", data}),
onSortChange: column => {
dispatch({type: "SORT_CHANGE", column})
},
onFilter: filterText => {
dispatch({type: "FILTER_CHANGE", filterText})
}
}
}


So now to the question. For some reason I don't understand ... if I console.log the
state.data
...everytime it gets sorted, the
state.data
gets mutated...which is not suppose to happen. But the real question is. why? Or do I missunderstand redux?

Answer

If you have a look at what .sort() actually does it says

The sort() method sorts the elements of an array in place and returns the array

So your mapStateToProps is actually mutating the state. There's nothing in redux that stops you from doing this, you have to take care of keeping the state immutable yourself.

This should be solved by using (for example)

return [...state.data].sort()

Or some other way to clone the array before sorting it.

You can replicate this in the browser console by running these two lines and comparing the output

var a = [2,1]; console.log(a.sort()); console.log(a)
var a = [2,1]; console.log([...a].sort()); console.log(a)

The first one will change the original array, the second will not.