State mutation was detected between dispatchers, but I did not mutate state

I know this question has been asked before, but almost all of them say that the OP is directly mutating the state which I tried to avoid using methods like the spread operator (both in objects and in arrays), but despite on from this I get 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 where the error points to , and it seems to me I checked if I had manually mutated the state in my reducer and I can't see that this can happen:

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 a part of the application that can be used to replicate an error that strangely happens only once every time I create a new course or try to edit an existing one (actions CREATE_COURSE_SUCCESS

and UPDATE_COURSE_SUCCESS

accordingly in mine courseReducer

)

Edit React-Redux (Question) - Challenges

enter image description here

enter image description here

I would really appreciate it if someone could help me figure out where the source of this error might be.

+3


source to share


1 answer


The problem is that you are in a mutating state internally CoursesPage.js

, in mapStateToProps

:

let courses = state.courses.sort((c1, c2) =>
  c1.title.localeCompare(c2.title, 'en', { sensitivity: 'base' }),
);

      

Array#sort

is in place , so it mutates the original array, sorting the original array into place. This means it sort

mutates state.courses

, thus causing an error. Instead, make a copy state.courses

before sorting it:

[...state.courses]

      

The above example uses spread syntax to spread elements into a new array, essentially cloning it. This is the same as Array#slice

. Then you can sort it like this:

let courses = [...state.courses].sort((c1, c2) =>
  c1.title.localeCompare(c2.title, 'en', { sensitivity: 'base' }),
);

      



This will not mutate the original one state.courses

and will not throw an error.


Note. There are also places where you mutate directly this.state

, for example on line 32 ManageCoursePage.js

where you do:

this.state.errors = {}

      

Only ever mutate an object this.state

in a component constructor. Use instead setState

.

+5


source







All Articles