开发者问题收集

浏览电影详细信息页面时,React 电影应用程序崩溃

2022-07-23
200

我正在创建一个使用 rapid API 中的电影应用 API 的 React 电影应用。主页上一切都运行正常,我能够以卡片的形式呈现所有电影。我已将应用设置为当用户点击电影卡片时,它应该直接转到 Moviedetail 页面。为此,我使用了 react-router-dom,并且一切都设置正确。单击电影卡片时,它会导航到 Moviedetail 页面,但没有任何内容被呈现,并在浏览器控制台中出现此错误。 (未捕获的 TypeError:无法读取未定义的属性(读取“长度”)在 Details(Details.js:18:1));

但如果我在 MovieDetails 页面中注释 Detail 和 MovieTrailers 组件并取消注释它,则 MovieDetails 页面上的所有内容都会完美呈现。如果我再次刷新页面,它会再次中断,我得到相同的浏览器控制台错误。

import React, {useState, useEffect} from "react";
import {Box} from "@mui/material";
import {useParams} from "react-router-dom";
import MovieTrailers from "../components/MovieTrailers";
import Details from "../components/Details";
import {fetchData, options} from "../utils/fetchData";

function MovieDetails() {
    
    const [movieDetailData, setMovieDetailData] = useState({});
    const [movieTrailerData, setMovieTrailerData] = useState([]);
    const {id} = useParams();
   

    // console.log(id);
    console.log(movieDetailData);
    console.log(movieTrailerData);

   

    useEffect(()=>{
            const fetchMovieData = async ()=> {

            const detailData = await fetchData(`https://movies-app1.p.rapidapi.com/api/movie/${id}`, options);
            setMovieDetailData(detailData.result);

            const trailerData = await fetchData(`https://movies-app1.p.rapidapi.com/api/trailers/${id}`, options);
            setMovieTrailerData(trailerData.result);
    }
    fetchMovieData();
    },[id]);
    
    return(
    <Box>
        <Details
            movieDetailData={movieDetailData}
        />
        <MovieTrailers 
            movieTrailerData={movieTrailerData}
        />
    </Box>)
}

export default MovieDetails;




////here is Details component

import React from "react";
import {Box, Stack, Typography, Chip} from "@mui/material";

function Details(props) {
    
    const{image, titleOriginal, countries, genres, rating, release, description} = props.movieDetailData;

    return <Stack direction="row" width="100%" sx={{backgroundColor:"#fff"}}>
        <img className="movie-poster" src={image} alt="movie-poster"/>
        <Stack p="50px" sx={{width:"60%"}}>
        <Typography variant="h2" fontWeight="700">
           {titleOriginal}
        </Typography>
        <Box pt="30px" sx={{display:"flex", gap:"30px"}}>
        <Chip label={<Typography variant="h6" fontWeight="700">{`rating : ${rating}`}</Typography>} />
        <Chip label={<Typography variant="h6" fontWeight="700">{`release: ${release}`}</Typography>} />
        </Box>
        <Typography variant="h6" pt="30px">
        {description.length>600 ? description.substring(0, 601) : description}
        </Typography>
        <Box pt="30px" sx={{display:"flex", gap:"30px"}}>
        <Chip label={<Typography variant="h6" fontWeight="700">{`genre : ${genres[0].name}`}</Typography>} />
        <Chip label={<Typography variant="h6" fontWeight="700">{`origin : ${countries[0].name}`}</Typography>} />
        </Box>
    </Stack>
</Stack>
}

export default Details;




////here is MovieTrailer component

import React from "react";
import {Box, Stack, Typography} from "@mui/material";
import TrailerCard from "./TrailerCard";
import {nanoid} from "nanoid";

function MovieTrailers({movieTrailerData}) {
    console.log(movieTrailerData);
    return <Box p="30px">
        <Typography variant="h4" pt="40px" pb="50px" fontWeight="700" m="auto">{`Watch ${movieTrailerData[0].title}`}
        </Typography>
        <Stack direction="row" justifyContent="space-between">
        {(movieTrailerData.slice(0, 3)).map((trailer)=>(
            <TrailerCard trailer={trailer}/>
        ))}
        </Stack>
    </Box>
}

export default MovieTrailers;


////here is TrailerCard component

import React from "react";
import {Box, Stack, Typography, Chip} from "@mui/material";

function TrailerCard({trailer}) {
    
    const{thumbnail, ago, author, views, title,  url, description} = trailer;

    return <Box className="trailer-card" p="10px" backgroundColor="#fff" width="25%">
        <Stack>
        <a
        className="movie-trailer-link"
        href={url}
        target="_blank"
        rel="noreferrer">
            <img className="movie-trailer-thumbnail" src={thumbnail} alt="movie-trailer"/>
        <Typography pt="10px" variant="body1" fontWeight="700" >
            {title}
        </Typography>
        <Stack paddingBlock="10px" direction="row" justifyContent="space-between" gap="10px" flexWrap="wrap">
        <Chip label={`views: ${views}`} />
        <Chip label={`ago: ${ago}`}/>
        </Stack>
        <Typography variant="subtitle2">{`YT: ${author.name}`}</Typography>
        <Typography variant="body2" pb="20px">
        {description}
        </Typography>
        </a>
        </Stack>
    </Box>
}

export default TrailerCard;
2个回答

在影片详情组件中,添加一个最初设置为 true 的加载状态。在 useEffect 中解析 A​​PI 调用后,将加载变量设置为 false。

在 jsx 中,如果加载为 false,则呈现页面数据,否则显示加载器或其他内容

kanuos
2022-07-23

在从后端获取数据之前,movieDetailData 是一个空对象。这就是您收到错误的原因。

首先检查您的 props 是否有合适的键。

import React from "react";
import {Box, Stack, Typography, Chip} from "@mui/material";

function Details(props) {

  if (Object.keys(props.movieDetailData).length == 0)
    return null;

  const{image, titleOriginal, countries, genres, rating, release, description} = props.movieDetailData;

  // rest of your code
}
Ahmet Firat Keler
2022-07-23