Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

140
Views
Error: An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft

I have my reducer


const userAuthSlice = createSlice({
    name: "userAuth",
    initialState: {
        token: '',
    },
    reducers: {
        setToken: (state, action) => state.token = action.payload.test,
    },
});

And I have my dispatch command

<button
   value={text.sign_in.submit}
   onClick={() => dispatch(userAuthSlice.actions.setToken({test:"test"}))}

/>

As I press the button what I get is this error:

enter image description here

I have isolated everything to be sure that this is the problem and nothing else.

Why does this error pop up?

over 4 years ago · Santiago Trujillo
7 answers
Answer question

0

The issue is the use of an arrow function with no curly braces as the reducer, because that acts as an implicit return statement. So, you're both mutating state.token, and returning the result of the assignment.

Per the Immer docs on returning data, there's a couple ways to fix this:

  • Adding the void operator in front of the assignment
  • Wrapping the assignment in curly braces to make it a function body

so setToken reducer can be updated with void as

setToken: (state, action) => void(state.token = action.payload.test)
over 4 years ago · Santiago Trujillo Report

0

Instead of

 state.token = action.payload.token

use

 const token = action.payload.token
 state.token = token

Constants are immutable, and assigning action.payload contents to a constant resolved a problem for me (Note that in case the payload is an object it is not necessary

Working example of createSlice:

import { createSlice } from '@reduxjs/toolkit';

export const slice = createSlice({
  name: 'login',
  initialState: {
      username: "Foo",
      password: "AAA",
      authorized : false
  },
  reducers: {
    setUsername: (state, action) => {

      const value = action.payload
      state.username = value // action.payload.username

    },
    setPassword: (state, action) => {

      const value = action.payload
      state.password = value // action.payload.password

    },
    logon: (state, action) => {

      state.username = action.payload.username
      state.password = action.payload.password
      state.authorized = true

    },
    logoff: state => state.authorized = false
  },
});
over 4 years ago · Santiago Trujillo Report

0

you may forget break; statement at your reducer.js file;

 case LOGIN_USER_ERROR_RESET:
        draft.errormsg = '';
        draft.loading = false;
        draft.error = false;
        break;
over 4 years ago · Santiago Trujillo Report

0

Points to learn about IMMER

  1. If you return anything other than draft from the recipe function, that return value will replace the state
  2. You mostly want to mutate the draft to mutate the state, ** so returning draft after modifying it is optional**, the immer will return finalized draft anyway
  3. if you return anything else from recipe function then as per point 1, the new return value will replace the state
  4. Point 3 is ok, only if you do not modify the draft in your recipe function. i.e. you can choose one of the two
    a. modify the draft --> return draft or undefined, either is ok
    b. want to return some new value, then don't touch the draft at all

Now coming to answer for the question. this is your reducer function

(state, action) => state.token = action.payload.test

This function is doing two things,
1. modifying state
2. returning action.payload.test

so it's violating point 4 and hence the error from Immer library

in this specific case, intention is only to modify the state, so we have to undo the existing return with void

setToken: (state, action) => void(state.token = action.payload.test)

However, Immer library recommends the use of code block to insure consistency across large code-base, this code block implicitly returns undefined

setToken: (state, action) => { state.token = action.payload.test } 
over 4 years ago · Santiago Trujillo Report

0

Try checking this link for Copying Without Reference

over 4 years ago · Santiago Trujillo Report

0

Correct answer

Use Instead of

const userAuthSlice = createSlice({
    name: "userAuth",
    initialState: {
        token: '',
    },
    reducers: {
        setToken: (state, action) => state.token = action.payload.test,
    },
});

Use this {I have just added brackets}

const userAuthSlice = createSlice({
    name: "userAuth",
    initialState: {
        token: '',
    },
    reducers: {
        setToken: (state, action) => { state.token = action.payload.test}, // <<= Change Here
    },
});
over 4 years ago · Santiago Trujillo Report

0

For those who are working with React PullState, my issue was with the syntax:

I had:

 const onUpdate = (value: any) => {
    someStore.update((s) => (s.value = value));
 };

but has to be:

 const onUpdate = (value: any) => {
    someStore.update((s) => {
       s.value = value;
    });
 };

For some reason, doesn't like the arrow function declared on the first approach.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!