2

I am practicing redux-toolkit with typescript. I have use one open api and for fetching data I used redux toolkit's createAsyncThunk. I successfully able to fetched the data in app's component. When I console log it, I can able to see the data but as soon I map the data.result I am getting error: TypeError: Cannot read property 'map' of undefined. I think I have made Typescript error when I used the interface. But don't see where is the problem and Also in Chrome's reduxdevtools: data expect object but I put arrays. This my redux-devtools looks like. I shared my code in Codesand Box.

PS: I am sharing only these two files below because I think this is where I making mistakes

This is my Reducer, I think I making mistake in types

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

export const dataFetch = createAsyncThunk(
  `store/dataFetch`,
  async () => {
    const url = `https://rickandmortyapi.com/api/character`;
    const response = await fetch(url);
    const data = await response.json();
    return data;
  }
);

interface Meta {
  loading: boolean;
  error: boolean;
  message: string;
}
// This is where I am making mistake
interface Results {
  name: string;
  image: string;
  gender: string;
  species: string;
  status: string;
}

interface Info {
  count: number;
  pages: number;
}

interface User {
  results: Results[];
  info: Info;

}

export interface IUser {
  meta: Meta;
  data: User[];
}

const initialState: IUser = {
  "meta": {
    "loading": false,
    "error": false,
    "message": ``
  },
  "data": []
};

const UserSlice = createSlice({
  "name": `JsonPlacehoder user`,
  initialState,
  "reducers": {

  },
  "extraReducers": (builder) => {
    builder.addCase(dataFetch.pending, (state) => (
      {
        ...state,
        "meta": {
          ...state.meta,
          "loading": true
        }
      }
    ));
    builder.addCase(dataFetch.fulfilled, (state, { payload }) => (
      {
        ...state,
        "meta": {
          ...state.meta,
          "loading": false,
          "error": false,
          "message": ``
        },
        "data": payload
      }
    ));
    builder.addCase(dataFetch.rejected, (state, { error }) => {
      window.alert(error?.message);
      return {
        ...state,
        "meta": {
          "loading": false,
          "error": true,
          "message": error?.message || ``
        }
      };
    });
  }
});

export default UserSlice.reducer;

This is my component where I am getting error when I using map function

import React, { useEffect } from 'react';

import { useSelector, useDispatch } from 'react-redux'

import { dataFetch } from './store/reducers';
import { IRootState } from './store/combineReducers';

function App() {

  const { data, meta } = useSelector((rootState: IRootState) => rootState.fetchUser);

  console.log(data);

  const dispatch = useDispatch()


  useEffect(() => {
    dispatch(dataFetch())
  }, [dispatch])

  return (
    <div className="App">
      {
        data.results.map(i => { //GETTING ERROR
          return <div>
            <h1>{i.name}</h1>
          </div>
        })
      }
    </div>
  );
}

export default App;

1 Answer 1

1

That is because you are trying to .map over the data before the fetch has even started.

Your useEffect triggers after the first render. Before that, you already tried to .map once. And even then, during loading, your component might rerender.

That in combination that some of your reducers tend to actually remove the data attribute instead of keeping data: [] (I'm looking at pending there) lead to data being undefined on some renders.

A TypeError is actually not a TypeScript error (these always begin with "ts" followed by a number), but a JavaScript runtime error. So you really have a "runtime crash" here.

Sign up to request clarification or add additional context in comments.

1 Comment

optional chaining is the solution data?.results?.map

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.