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?
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.