Umut Palabiyik
Umut Palabiyik

Reputation: 323

getting TypeError: movieDetails.map is not a function when try to use useState in useEffect

import { useSelector, useDispatch } from "react-redux";
import { useEffect, useState } from "react";
import request from "../../requests";
import { fetchMovies } from "../../feautures/movies/moviesSlice";
import "./SingleMoviePage.scss";
import Rating from "../../components/UI/Rating/Rating";
import axios from "axios";

const SingleMoviePage = ({ match }) => {
  const dispatch = useDispatch();
  const [movieDetails, setMovieDetails] = useState({})

  /*  params */
  const movieId = match.params.id;
  const page = match.params.page;
  const genre = match.params.genre;

  /* movies reducer handle */
  const movies = useSelector((state) => state.movies.movies);
  const moviesStatus = useSelector((state) => state.movies.status);

  /* movieDetails reducer handle */


  /* base urls */
  const baseImgUrl = "https://image.tmdb.org/t/p/original";
  const movieDetailUrl = `https://api.themoviedb.org/3/movie/${movieId}?api_key=c057c067b76238e7a64d3ba8de37076e&language=en-US`;


  
  useEffect(() => {
    const fetchData = async() => {
      let response = await axios.get(movieDetailUrl);
      response = response.data;
      setMovieDetails(response)
    }

    fetchData()

  },[movieDetailUrl])
  console.log("data: ",movieDetails )

  


  let content;
  if (moviesStatus === "loading") {
    <div>Loading ...</div>;
  } else if (moviesStatus === "succeeced") {
    let movie = movies.find((movie) => movie.id.toString() === movieId);
    content = (
      <div
        className="single-movie__container"
        style={{
          backgroundImage: `url(${
            movie.backdrop_path
              ? baseImgUrl + movie.backdrop_path
              : baseImgUrl + movie.poster_path
          })`,
        }}
      >
        <div className="single-movie__information">
          <h1 className="single-movie__title">{movie.title}</h1>
          <div className="single-movie__rate">
            <Rating
              rating={movie.vote_average}
              className="single-movie__stars"
            />
            <div className="single-movie__average">
              {movie.vote_average}(Imdb)
            </div>
          </div>
          <p className="single-movie__overview">{movie.overview}</p>
          <p className="single-movie__genres">
            <label>Genres</label>
            {
              movieDetails.genres.map(genre => {
                console.log("genre: ",genre)
                return(
                  <div>{genre.name}</div>
                )
              })
            }
          </p>
        </div>
      </div>
    );
  }

  useEffect(() => {
    if (genre === "POPULAR") {
      dispatch(fetchMovies(request.fetchPopular(page)));
    } else if (genre === "NOW PLAYING") {
      dispatch(fetchMovies(request.fetchNowPlaying(page)));
    } else if (genre === "UP COMING") {
      dispatch(fetchMovies(request.fetchUpComing(page)));
    }
  }, [dispatch, genre, page]);

  return <div className="single-movie">{content}</div>;
};

export default SingleMoviePage;

I'm trying to make a movie website with react-redux. The issue is when I try to get movie details using useEffect and try to map that in:

<p className="single-movie__genres">

I get TypeError: Cannot read property 'map' of undefined error and I get empty object (data: {}) using console.log("data: ", movieDetails).

But if I refresh the page everything works well and I get data:

{
    adult: false, 
    backdrop_path: "/6MKr3KgOLmzOP6MSuZERO41Lpkt.jpg",
    ...
}

using console.log("data: ", movieDetails). Why can't I get data when the page is first loaded?

Upvotes: 0

Views: 181

Answers (3)

Umut Palabiyik
Umut Palabiyik

Reputation: 323

There is a point that i dont understand.As far as i know when the component is first loaded first useEffect worked and filled my movieDetails with datas after that map func worked.I mean js works top to bottom and shouldn't movieStatus be filled with data until it comes to the map function?

Upvotes: 0

sazzad
sazzad

Reputation: 525

.map method is a prototype function for type array. you should declare moviedetails as an array like this when setting the default value using useState hook.

const [movieDetails, setMovieDetails] = useState([])

Upvotes: 1

Tarukami
Tarukami

Reputation: 1160

It is because your initial state does not contain "genres" array inside the object. And when react tries to handle

movieDetails.genres.map(...)

it fall down because movieDetails.genres is undefined (and undefined does not support map method of course). Either include empty array in you initial state like:

const [movieDetails, setMovieDetails] = useState({genres:[]})

or use "?" operator in your chain like:

movieDetails.genres?.map(...)

Upvotes: 1

Related Questions