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