State

state/immer-mutate-or-return

A Redux Toolkit or Immer reducer either mutates the draft or returns a new state, never both; no arrow that returns a mutation.

seriousstaticfe-state

Why

Inside createSlice and createReducer, Immer lets a reducer "mutate" a draft. It also accepts a returned new state, but not both at once. An arrow with an expression body, such as (state, action) => state.push(action.payload), mutates the draft and returns the array length, and Immer throws when the action is dispatched.

Fix

Give the arrow a block body ((state, action) => { state.push(action.payload) }), or put void before the mutation. To replace the state instead, return a new value and leave the draft alone: (state, action) => state.filter((t) => t.id !== action.payload).

Examples

// bad
todoAdded: (state, action) => state.push(action.payload),
// good
todoAdded: (state, action) => {
  state.push(action.payload)
},
todoRemoved: (state, action) => state.filter((t) => t.id !== action.payload),

Sources

Facts

Id
state/immer-mutate-or-return
Severity
serious
Check
static checked in the source by audit
Applies to
jsx
Only in projects with
redux
Taught by the skill
fe-state State and stores
Since version
0.1.0

Rule file on GitHub

Read it in the terminal

npx github:dawidolko/frontend-skills explain state/immer-mutate-or-return