Tharun
Tharun

Reputation: 43

Unhandled Rejection (TypeError): state.push is not a function while using redux thunk

I'm getting this error Unhandled Rejection (TypeError): state.push is not a function while using redux thunk but while refrshing the page after error, new word is getting added to the DB.

Below is my code.

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";

export const getDictionaryAsync = createAsyncThunk(
  "dictionary/getDictAsync",
  async () => {
    let res = await fetch("https://vocabulary-app-be.herokuapp.com/dictionary");
    if (res.ok) {
      let dictData = await res.json();
      return { dictData };
    }
  }
);

export const addWordtoDictAsync = createAsyncThunk(
  "dictionary/addWordtoDictAsync",
  async (payload) => {
    let res = await fetch(
      "https://vocabulary-app-be.herokuapp.com/dictionary",
      {
        method: "POST",
        body: JSON.stringify({ word: payload.word }),
        headers: {
          "Content-Type": "application/json",
        },
      }
    );
    if (res.ok) {
      let data = await res.json();
      console.log(data);
      return { data };
    }
  }
);

const dictionarySlice = createSlice({
  name: "dictionary",
  initialState: [],
  reducers: {},
  extraReducers: {
    [getDictionaryAsync.fulfilled]: (state, action) => {
      return action.payload.dictData;
    },
    [addWordtoDictAsync.fulfilled]: (state, action) => {
      console.log(action.payload.data + "reducer");
      state.push(action.payload.data);
    },
  },
});

export default dictionarySlice.reducer;

Upvotes: 2

Views: 681

Answers (1)

Drew Reese
Drew Reese

Reputation: 203587

Issue

The issue is that the first call to get the dictionary mutates the state invariant, from array to object. The JSON response object from "https://vocabulary-app-be.herokuapp.com/dictionary" is an object with message and data keys.

{
  "message": "Your data is here",
  "data": [ .... your dictionary data array ]
}

The getDictionaryAsync returns an object with dictData key.

export const getDictionaryAsync = createAsyncThunk(
  "dictionary/getDictAsync",
  async () => {
    let res = await fetch("https://vocabulary-app-be.herokuapp.com/dictionary");
    if (res.ok) {
      let dictData = await res.json();
      return { dictData }; // <-- returned in action payload
    }
  }
);

And the reducer case sets state to this payload value.

[getDictionaryAsync.fulfilled]: (state, action) => {
  return action.payload.dictData;
},

Now your state is:

{
  "message": "Your data is here",
  "data": [ .... your dictionary data array ]
}

And can't be pushed into.

Solution

I think you just want the dictData.data array as the payload, or just the data property straight from a returned dictData object.

export const getDictionaryAsync = createAsyncThunk(
  "dictionary/getDictAsync",
  async () => {
    let res = await fetch("https://vocabulary-app-be.herokuapp.com/dictionary");
    if (res.ok) {
      let dictData = await res.json();
      return dictData.data; // <-- returned data property as payload
    }
  }
);

...

[getDictionaryAsync.fulfilled]: (state, action) => {
  return action.payload; // <-- return data payload as state
},

Upvotes: 1

Related Questions