I know this question has been asked before, but in almost all of them talk about the OP mutating the state directly, which I've tried to avoid using techniques like the spread operator (in both objects and arrays) but in spite of that I'm getting the following error:
Uncaught Error: A state mutation was detected between dispatches, in the path `courses.0`. This may cause incorrect behavior. (http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)
at invariant (eval at <anonymous> (bundle.js:922), <anonymous>:40:15)
at eval (eval at <anonymous> (bundle.js:3825), <anonymous>:50:36)
at eval (eval at <anonymous> (bundle.js:3846), <anonymous>:14:16)
at dispatch (eval at <anonymous> (bundle.js:3853), <anonymous>:37:18)
at eval (eval at <anonymous> (bundle.js:1151), <anonymous>:63:5)
at eval (eval at <anonymous> (bundle.js:3846), <anonymous>:11:18)
at Object.eval [as saveCourse] (eval at <anonymous> (bundle.js:3860), <anonymous>:4:12)
at Object.ManageCoursePage._this.saveCourse [as onSave] (eval at <anonymous> (bundle.js:2080), <anonymous>:134:27)
at CourseForm._this.onHandleSave (eval at <anonymous> (bundle.js:2052), <anonymous>:93:19)
at Object.ReactErrorUtils.invokeGuardedCallback (eval at <anonymous> (bundle.js:1301), <anonymous>:69:16)
I read the article that the error points to, and as it suggests I checked if I was manually mutating the state in my reducer and I can't see where that could be happening:
const courseReducer = (state = initialState.courses, action) => {
switch (action.type) {
case types.LOAD_COURSE_SUCCESS:
return action.courses;
case types.CREATE_COURSE_SUCCESS:
//This action throw the error
debugger;
return [
...state,
Object.assign({}, action.course)
];
case types.UPDATE_COURSE_SUCCESS:
//This action throw the error
debugger;
return [
...state.filter(course => course.id !== action.course.id),
Object.assign({}, action.course)
];
case types.DELETE_COURSE_SUCCESS:
return [...state.filter(course => course.id !== action.courseId)];
default:
return state;
}
};
Here's a sandbox with part of the application that can be used to replicate the error, which weirdly only happens from times to times when I create a new course or try to edit an existing one (actions CREATE_COURSE_SUCCESS and UPDATE_COURSE_SUCCESSrespectively in my courseReducer)


I'd really appreciate if anyone could help me figure out where could be lying the source of this error.
The problem is that you are mutating state, inside CoursesPage.js, in mapStateToProps:
let courses = state.courses.sort((c1, c2) =>
c1.title.localeCompare(c2.title, 'en', { sensitivity: 'base' }),
);
Array#sort is an in place operation, so it mutates the source array by sorting the source array in place. That means, sort is mutating state.courses, thus causing the error. Instead, make a copy of state.courses before you sort it:
[...state.courses]
The above uses spread syntax to spread the elements into a new array essentially cloning it. This is the same as Array#slice. Then you can sort it like so:
let courses = [...state.courses].sort((c1, c2) =>
c1.title.localeCompare(c2.title, 'en', { sensitivity: 'base' }),
);
This will not mutate the original state.courses and will not throw an error.
Note: There are also some places where you are mutating this.state directly, such as in line 32 of ManageCoursePage.js where you do:
this.state.errors = {}
Only ever mutate the this.state object in the constructor of the component. Use setState instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With