最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Immer only supports setting array indices and the 'length' property - Stack Overflow

programmeradmin4浏览0评论

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;

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;
Share Improve this question edited Aug 28, 2022 at 16:55 remarcoble 6831 gold badge6 silver badges20 bronze badges asked Jun 19, 2021 at 12:12 user275564user275564 3181 gold badge3 silver badges11 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 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",
        });
      });
  },
});

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 :).

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: '',
          }]
      }]
}

I ran into this error when using the built in CRUD functions that e with createEntityAdaptor. It was due to using setMany instead of setAll when updating my state with an array of objects.

docs

发布评论

评论列表(0)

  1. 暂无评论