reduxmiddlewarestoreredux-toolkitmutation

What does the immutability check middleware do in Redux Toolkit?


I am trying to learn Redux Toolkit and came across the default middleware for configureStore():

According to this page:

Immutability check middleware: deeply compares state values for mutations. It can detect mutations in reducers during a dispatch, and also mutations that occur between dispatches (such as in a component or a selector). When a mutation is detected, it will throw an error and indicate the key path for where the mutated value was detected in the state tree. (Forked from redux-immutable-state-invariant.)

I am confused. Aren't the reducers and dispatch function supposed to mutate state values? Why should errors ever be thrown?


Solution

  • It's easy to accidentally mutate state in your component.

    Imagine you have something like

    const myList = useSelector(state => state.foo.bar)
    myList.sort()
    

    that was an accidental state mutation - since myList is a reference to your store, and .sort() mutates an array instead of creating a new, sorted copy of it.

    That is a bug that often goes unnoticed for a while until you get very weird an hard to debug bugs in your application.

    As for reducers being allowed to mutate state: yes and no. In an immer reducer like in createSlice, you are allowed to write mutating logic, but under the hood it will create a new copy of the old state and never "mutate" the old state - so that is safe. But if you are hand-writing a reducer, it is very easy to do the same as above - a call to .sort() or .push and you accidentally modified the old store value.

    And that middleware checks both of that: accidental mutation outside of reducers, as well as accidental mutation in hand-written ones.