开发者问题收集

在 useEffect 中尝试使用 useState 时出现 TypeError: movieDetails.map 不是函数

2021-07-04
177
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;

我正在尝试使用 react-redux 制作一个电影网站。问题是当我尝试使用 useEffect 获取电影详细信息并尝试将其 map 到:

<p className="single-movie__genres">

我收到 TypeError:无法读取未定义的属性“map” 错误,并且我使用 console.log("data: ", movieDetails) 获得空对象 ( data: {})。

但如果我刷新页面,一切都会正常,我得到 data:

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

使用 console.log("data: ", movieDetails) 。为什么我在第一次加载页面时无法获取数据?

3个回答

这是因为您的初始状态不包含对象内的“genres”数组。当 React 尝试处理

movieDetails.genres.map(...)

时,它会失败,因为 movieDetails.genres 未定义(并且未定义当然不支持 map 方法)。要么在您的初始状态中包含空数组,例如:

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

,要么在您的链中使用“?”运算符,例如:

movieDetails.genres?.map(...)
Tarukami
2021-07-04

.map 方法是数组类型的原型函数。在使用 useState 钩子设置默认值时,您应该将 moviedetails 声明为这样的数组。

const [movieDetails, setMovieDetails] = useState([])
sazzad
2021-07-04

有一点我不明白。据我所知,当组件首次加载时,useEffect 起作用了,然后在 map 函数起作用之后,用数据填充了我的 movieDetails。我的意思是 js 从上到下工作,而 movieStatus 不应该在到达 map 函数之前填充数据吗?

Umut Palabiyik
2021-07-04