Home > Software design >  Fetching data using props - Cannot read properties of undefined (reading 'map')
Fetching data using props - Cannot read properties of undefined (reading 'map')

Time:04-10

I'm making a movie app in React.

For fetching data I'm using a custom hook named useFetch

I'm fetching a list of genres in Genre. Based on the genre id I'm creating a new route to render a list of movies in MoviesFromGenre. Using the movie's id, when I click on a Movie component I'm making a new route to a MovieDetails component.

In MovieDetails I want to add a Credits component. For that, I'm passing the movie id as props, then based on that id I'm fetching a list of the movie credits, but when I'm mapping the array I get this error: Cannot read properties of undefined (reading 'map')

Sandbox link

useFetch

import { useReducer, useEffect } from "react";
import axios from "axios";

const ACTIONS = {
  FETCH_DATA: "fetch-data",
  ERROR: "error"
};

const initialState = {
  data: [],
  loading: false,
  error: null
};

function reducer(state, { type, payload }) {
  switch (type) {
    case ACTIONS.FETCH_DATA:
      return { data: payload, loading: false };
    case ACTIONS.ERROR:
      return { data: [], error: payload };
    default:
      return state;
  }
}

function useFetch(url, data) { // Passing a data argument is necessary: https://stackoverflow.com/questions/71668249/cant-map-fetched-data-from-custom-usefetch-hook
  const [state, dispatch] = useReducer(reducer, {...initialState, data});
  useEffect(() => {
    axios
      .get(url)
      .then((res) => {
        dispatch({ type: ACTIONS.FETCH_DATA, payload: res.data });
      })
      .catch((e) => {
        dispatch({ type: ACTIONS.ERROR, payload: e.error });
      });
  }, [url]);
  return state;
}
export default useFetch;

MovieDetails

import React, { useState } from "react";
import { useParams } from "react-router-dom";
import Credits from "../Credits/Credits";
import useFetch from "../Utils/useFetch";
import "../Utils/useFetch";
import { API_KEY, API_URL } from "../../api/requests";

function MovieDetails() {
  const { movieId } = useParams();
  const BASE_URL = `${API_URL}/movie/${movieId}?api_key=${API_KEY}`;
  const { data: movie, loading, error } = useFetch(BASE_URL, { movie: [] });
  console.log(movie);
  return (
    <div className="movie-details">
      {movie.title}
      <Credits movieId={movie.id} />
    </div>
  );
}

export default MovieDetails;

Credits

import React from "react";
import useFetch from "../Utils/useFetch";
import { API_KEY, API_URL } from "../../api/requests";

function Credits(props) {
  const { movieId } = props;
  const BASE_URL = `${API_URL}/movie/${movieId}/credits?api_key=${API_KEY}`;
  const { data: credits, loading, error } = useFetch(BASE_URL, { credits: [] });
  console.log(movieId);
  return (
    <div className="credits">
      {credits.id}
      {loading
        ? "Loading"
        : credits.credits.cast.map((castMember) => <h1>{castMember}</h1>)}
      {error ? error : null}
    </div>
  );
}

export default Credits;

CodePudding user response:

The issue you have here seems to be that you are trying to access an object credits inside credits where you can already access cast.

{loading ? (
    "Loading"
  ) : credits && credits.cast ? (
    credits.cast.map((castMember) => <h1>{castMember.id}</h1>)
  ) : (
    <div>{"Error fetching credits"}</div>
  )}

works for me. I've added an extra check for credits and credits.cast just to avoid trying to access that object when undefined. I've also changed <h1>{castMember}</h1> to <h1>{castMember.id}</h1> because I then got an error that the object wasn't a valid react child, so just printing out the id here to show that you can now access the properties of castMember.

Here's the updated sandbox: https://codesandbox.io/s/tmdb-credits-forked-xwqp1b?file=/src/Components/Credits/Credits.js:428-630

  • Related