开发者问题收集

React:未捕获的类型错误:无法读取未定义的属性(读取‘jpg’)

2022-05-12
1085

我是 React 新手,我正在尝试从 jikan 中随机挑选一部动漫,它将返回一个包含关键图像的对象(一个对象)。图像包含关键 jpg。它一直说“无法读取未定义的属性(读取‘jpg’)”。请帮忙!非常感谢

这是主要组件:

import React, { useState, useEffect } from "react";
import "./animedb.css";
import TopAnime from "./topanime";
import AnimeSearch from "./animesearch";
import AnimeRandom from "./animerandom";
import AnimeDisplay from "./animedisplay";
import NavBar from "./navbar";

const AnimeDB = () => {
  const [animeList, setAnimeList] = useState([]);
  const [isRandomAnime, setIsRandomAnime] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [topAnime, setTopAnime] = useState([]);
  const [searchAnime, setSearchAnime] = useState("");
  const [randomAnime, setRandomAnime] = useState({});
  const url = "https://api.jikan.moe/v3";

  const ShowAnime = async () => {
    let display_url = url + "/season/2022/spring";
    const response = await fetch(display_url);
    const result = await response.json();
    setAnimeList(result.anime.slice(0, 10));
    setIsLoading(false);
  };
  useEffect(() => {
    ShowAnime();
    FindTopAnime();
  }, []);

  const FindTopAnime = async () => {
    let top_url = url + "/top/anime/1/bypopularity";
    try {
      const res = await fetch(top_url);
      const result = await res.json();
      setTopAnime(result.top.slice(0, 5));
    } catch (error) {
      console.log(error);
    }
  };

  const FindSearchAnime = async (query) => {
    setIsLoading(true);
    try {
      const res = await fetch(
        `https://api.jikan.moe/v3/search/anime?q=${query}&order_by=title&sort=asc`
      );
      const result = await res.json();
      setAnimeList(result.results.slice(0, 10));
      setIsLoading(false);
    } catch (error) {
      console.log(error);
    }
  };
  const handleSearch = (e) => {
    e.preventDefault();
    FindSearchAnime(searchAnime);
  };

  const handleRandom = async () => {
    setIsLoading(true);
    setIsRandomAnime(true);
    let res = await fetch("https://api.jikan.moe/v4/random/anime");
    let result = await res.json();
    setRandomAnime(result.data);
    setIsLoading(false);
    console.log(result.data);
  };
  return (
    <div className="wrapperAnime">
      {/* <NavBar /> */}
      <h1 id="appName">
        u<strong id="strong">ME</strong>i
      </h1>
      <div className="container">
        <TopAnime topAnime={topAnime} />
        <div className="display">
          <button onClick={handleRandom}>Random Anime</button>
     
          <AnimeSearch
            onSearch={handleSearch}
            setSearchAnime={setSearchAnime}
            value={searchAnime}
          />
          <AnimeDisplay
            isLoading={isLoading}
            animeList={animeList}
            isRandomAnime={isRandomAnime}
            randomAnime={randomAnime}
            setIsRandomAnime={setIsRandomAnime}
          />
        </div>
      </div>
    </div>
  );
};
export default AnimeDB;

组件:AnimeDisplay:

function AnimeDisplay(props) {
  if (props.isRandomAnime) {
    let { mal_id, title, images } = props.randomAnime;
    return (
      <div className="collections">
        <div key={mal_id} className="card">
          <h1>{title}</h1>
          <img src={images.jpg.image_url} alt="test" />
        </div>
      </div>
    );
  } else {
    return (
      <div className="collections">
        {props.animeList.map((ele) => {
          const { mal_id, image_url, title, episodes } = ele;
          if (props.isLoading) {
            return <h1>Loading...</h1>;
          }
          return (
            <div key={mal_id} className="card">
              <img src={image_url} alt="" />
              <h1>{title}</h1>
            </div>
          );
        })}
      </div>
    );
  }
}
export default AnimeDisplay;

#更新:我试过你的方法,但也没用。这是返回的数据:

{mal_id: 43450, url: 'https://myanimelist.net/anime/43450/Shao_Nian_Effendi', images: {…}, trailer: {…}, title: 'Shao Nian Effendi', …}aired: {from: '2012-01-01T00:00:00+00:00', to: null, prop: {…}, string: '2012 to ?'}airing: falsebackground: nullbroadcast: {day: null, time: null, timezone: null, string: 'Unknown'}demographics: [{…}]duration: "12 min per ep"episodes: 104explicit_genres: []favorites: 0genres: []images: jpg: image_url: "https://cdn.myanimelist.net/images/anime/1248/118197.jpg"large_image_url: "https://cdn.myanimelist.net/images/anime/1248/118197l.jpg"small_image_url: "https://cdn.myanimelist.net/images/anime/1248/118197t.jpg"[[Prototype]]: Objectwebp: {image_url: 'https://cdn.myanimelist.net/images/anime/1248/118197.webp', small_image_url: 'https://cdn.myanimelist.net/images/anime/1248/118197t.webp', large_image_url: 'https://cdn.myanimelist.net/images/anime/1248/118197l.webp'}[[Prototype]]: Objectlicensors: []mal_id: 43450members: 31popularity: 19210producers: []rank: 14029rating: "PG - Children"score: nullscored_by: nullseason: nullsource: "Other"status: "Finished Airing"studios: []synopsis: nullthemes: []title: "Shao Nian Effendi"title_english: nulltitle_japanese: "少年阿凡提"title_synonyms: (3) ['Shao Nian A Fan Ti', 'Shao Nian Afanti', 'Young Effendi']trailer: {youtube_id: null, url: null, embed_url: null, images: {…}}type: "TV"url: "https://myanimelist.net/anime/43450/Shao_Nian_Effendi"year: null[[Prototype]]: Object
2个回答

我认为这是因为您的初始状态没有任何“jpg”键,并且当它第一次读取您的代码时(在 useEffect 之前)它会引发错误。您可以(错误的方式!)像这样更新您的初始状态: useState([{images:{jpg:""}}]) 或正确的方式,即条件渲染!

Shahryar_Jahanshahloo
2022-05-12

正如 Shahryar_Jahanshahloo 所说,您必须为初始状态提供默认值,因此请按如下方式更改 randomAnime

// note that the object is much more greater than this, but I only included
// the properties that you are using

const [randomAnime, setRandomAnime] = useState({
  mal_id: "",
  title: "",
  images: { jpg: { image_url: "" } }
});

我注意到的另一件错误是您的 AnimeDisplay 中的加载状态,您应该执行以下操作:

function AnimeDisplay(props) {
  const { mal_id, title, images } = props.randomAnime;
  
  // move the loading conditional to outside of the mapping
 // so when the component is fetching the data it only
// renders the loading element
  if (props.isLoading) {
    return <h1>Loading...</h1>;
  }
  
  // after the fetch you can render your components normally
  if (props.isRandomAnime) {
    return (
      <>
        <div className="collections">
          <div key={mal_id} className="card">
            <h1>{title}</h1>
            <img src={images?.jpg.image_url} alt="test" />
          </div>
        </div>
      </>
    );
  } else {
    return (
      <div className="collections">
        {props.animeList.map((ele) => {
          const { mal_id, image_url, title, episodes } = ele;

          return (
            <div key={mal_id} className="card">
              <img src={image_url} alt="" />
              <h1>{title}</h1>
            </div>
          );
        })}
      </div>
    );
  }
}
Yago Biermann
2022-05-12