3

What types of things would cause Immer only supports setting array indices and the 'length' property' from the code below? This FoodLogState type is a class. I've done something very similar with no issue. I notice I am not updating even the array from state yet. Only the status that is a string.

    import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
    import { FoodLogState, getFoodState } from "../AccountAPI";
    
    export interface FoodLogs {
      foodLogs: Array<FoodLogState>;
      status: "idle" | "loading" | "failed";
    }
    
    const initialState: FoodLogs = {
      foodLogs: null,
      status: "idle",
    };
    
    export const getFoodLogsAsync = createAsyncThunk(
      "foodsLogged/getFoodsLogged",
      async (uid: string, { rejectWithValue }) => {
        try {
          const response = await getFoodState(uid).catch((error) => {
            return rejectWithValue(error.message);
          });
          return response;
        } catch (error) {
          return rejectWithValue(error.message);
        }
      }
    );
    
    const foodsLogSlice = createSlice({
      name: "foodsLogged",
      initialState,
      reducers: {},
      extraReducers: (builder) => {
        builder
          .addCase(getFoodLogsAsync.fulfilled, (state, action) => {
            //state.foodLogs = action.payload;
            state.status = "idle";
          })
          .addCase(getFoodLogsAsync.rejected, (state, action) => {
            state.status = "failed";
          })
          .addCase(getFoodLogsAsync.pending, (state) => {
            state.status = "loading";
          });
      },
    });
    
    export const selectFoods = (state) => state.foodLog;
    
    export default foodsLogSlice.reducer;
remarcoble
  • 537
  • 1
  • 4
  • 19
user275564
  • 163
  • 1
  • 2
  • 10

3 Answers3

0

This will get the code running but if anyone knows the underlying issue, I would accept that answer because it is 'more correct.' I believe this answer just bypasses Immer in Redux Toolkit, not exactly ideal.

const foodsLogSlice = createSlice({
  name: "foodsLogged",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(getFoodLogsAsync.fulfilled, (state, action) => {
        //similar error to the link below,
        //status: "idle" causes immer error.
        //http://5.9.10.113/67418074/redux-thunk-modifying-state-unhandled-promise-rejection-error-immer-immer
        return (state = {
          ...state,
          status: "idle",
          foodLogs: action.payload,
        });
      })
      .addCase(getFoodLogsAsync.rejected, (state, action) => {
        return (state = {
          ...state,
          status: "failed",
        });
      })
      .addCase(getFoodLogsAsync.pending, (state) => {
        return (state = {
          ...state,
          status: "loading",
        });
      });
  },
});
Nickofthyme
  • 3,032
  • 23
  • 40
user275564
  • 163
  • 1
  • 2
  • 10
  • 1
    Your `return (state = {` should just be `return {`. No assignment to the state variable will have any effect. https://redux-toolkit.js.org/usage/immer-reducers#resetting-and-replacing-state Generally, your array might have additional properties that immer is not expecting. Also, we recommend not to put class instances in Redux. https://redux.js.org/style-guide/style-guide/#do-not-put-non-serializable-values-in-state-or-actions – phry Jun 19 '21 at 22:10
0

I am using redux-thunk and had this same issue. Tried several things but couldn't get it to work.

I had the idea of running it in a private window. I logged in and opened the page where this error occurred (on my fetchUserTypes action) and it worked fine.

I realized it is caused by some cached data and that is when I had the idea to clear my local storage (I am using redux-thunk which stores the redux state in local storage).

This will not result in an error if you only use JavaScript - seems like it only happens when you use TypeScript and you modify the structure of your reducer.

I am leaving this here because this has happened to me twice and I opened this link both times and in both cases I was able to solve the problem only after clearing local storage. Next time I decide to modify the structure of my reducer and run into this error I will be one step ahead :).

no_modules
  • 117
  • 7
0

I was having the same issue and I hope this example gives a little light. In my case, the problem was that I was setting the whole initialState keys (id, servings, bookmarks) conditionally. Among these; "bookmarks" gets defined later in the app (and it was the only one taken from localStorage).

const getLocalStorage = () => {<... some code>}
const initialState = getLocalStorage()

The solution for me was to set a condition to "bookmarks" at the initial state using the ternary operator:

const storage = localStorage.getItem('bookmarks')

const initialState = {
    id: '',
    servings: 0,
    bookmarks: storage ? JSON.parse(storage) : [{
        id: '',
        title: '',
        publisher: '',
        image_url: '',
        servings: '',
        cookingTime: '',
        ingredients: [{
            quantity: 0,
            unit: '',
            description: '',
          }]
      }]
}