Immer - Get error with async function in produce

3.8k Views Asked by At

I'm trying to create an asynchronous produce with immer but I get an error when I call this async function :

This my code :

import { combineReducers, createStore } from 'redux';
import produce from 'immer';

const mainReducer = produce(async (draft, { type, payload }: { type: string; payload: any }) => {
    switch (type) {
        case 'foo': {
            draft = await myAsyncFn(payload);
        }
    }
});

const reducers = {
    main: mainReducer,
};

const rootReducer = combineReducers(reducers);

export const mainStore = createStore(rootReducer);

This is the output : Error: [Immer] produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '[object Promise]'

Why doesn't it work ? (I thought It's was possible : https://immerjs.github.io/immer/docs/async)

What does it mean by classes that are marked with '[immerable] ?

2

There are 2 best solutions below

0
On

While Immer does appear to let you write async logic inside of produce, you must never write async logic in a Redux reducer.

Having said that, the specific error here is because by default, Immer only knows how to update plain JS objects and arrays. In order to update a class instance or similar, you have to add a special immerable symbol to that class type.

Note that you should be using Immer with Redux, but as part of our official Redux Toolkit package, which has Immer built into its createSlice API.

0
On

Might not be so relevant but I got this error using redux-toolkit. The createSlice() method was working well until I changed the type of the state to a generic typescript type. Then it started throwing the mentioned error.

import { AsyncState } from "./AsyncState";

export class SliceState<T> {
  constructor(initialState: T) {
    this.data = initialState;
    this.status = new AsyncState();
  }
  status: AsyncState;
  data: T;
}

Additional error information: [Immer] produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '[object Object]'