React出现Cannot read properties of undefined错误,图片加载失败求助
问题解决:无法获取球员图片并出现
Cannot read properties of undefined (reading 'then')错误 错误根源
fetchImages函数未返回Promise:你定义的fetchImages内部执行了Promise.all但没有返回结果,调用fetchImages().then()时,函数返回undefined,而undefined没有.then()方法,直接触发报错。- 渲染逻辑错误:即使图片数据获取成功,当前在每个球员卡片中遍历所有图片,会导致每个卡片显示所有球员的图片,而非对应球员的图片。
修复步骤
1. 修复fetchImages函数
修改函数使其返回Promise,并保留id与图片的关联,方便后续匹配球员:
const fetchImages = async (ids) => Promise.all(ids.map(async (id) => ({ id, image: await fetchImage(id) })));
2. 优化数据关联与渲染
推荐将姓名和图片数据合并,避免渲染时的混乱,以下是两种可行方案:
方案A:合并请求,统一管理球员数据
同时发起姓名和图片请求,合并为包含完整信息的数组,渲染更简洁:
export default function _quarterbacksPage() { const [players, setPlayers] = useState([]); useEffect(() => { const fetchPlayers = async () => { try { // 同时发起两个请求,提升性能 const [namesData, imagesData] = await Promise.all([ fetchFullNames(quarterbacks), fetchImages(quarterbacks) ]); // 根据id合并数据 const mergedPlayers = namesData.map(nameItem => { const imageMatch = imagesData.find(img => img.id === nameItem.id); return { ...nameItem, image: imageMatch ? imageMatch.image : '' }; }); setPlayers(mergedPlayers); } catch (err) { console.error(err); } }; fetchPlayers(); }, []); return ( <> <_navbar /> {players.map(({ id, name, image }) => ( <div className={styles.card} key={id}> {image && <img src={image} alt={`${name}的球员照片`} />} <Link className={styles.cardText} to={`/quarterback/${id}`}> {name} </Link> </div> ))} </> ); }
方案B:单独维护数据,渲染时匹配id
如果要保留两个独立状态,渲染时通过id找到对应图片:
export default function _quarterbacksPage() { const [names, setNames] = useState([]); const [images, setImages] = useState([]); useEffect(() => { fetchFullNames(quarterbacks).then(setNames).catch(console.error); fetchImages(quarterbacks).then(setImages).catch(console.error); }, []); return ( <> <_navbar /> {names.map(({ id, name }) => { const playerImage = images.find(img => img.id === id)?.image; return ( <div className={styles.card} key={id}> {playerImage && <img src={playerImage} alt={`${name}的球员照片`} />} <Link className={styles.cardText} to={`/quarterback/${id}`}> {name} </Link> </div> ); })} </> ); }
完整修复后代码示例
结合方案A的完整代码:
import { Link } from "react-router-dom"; import _navbar from "../../NavBar/navbar"; import React, { useEffect, useState } from "react"; import styles from "./card.module.css"; const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417]; const fetchFullName = async (id) => { const res = await fetch( `https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=${encodeURIComponent(id)}`, { headers: { "x-rapidapi-key": "secret key", "x-rapidapi-host": "nfl-api-data.p.rapidapi.com", }, }, ); if (!res.ok) { throw new Error(`Name lookup for id '${id}' failed`); } return (await res.json()).athlete.fullName; }; const fetchFullNames = async (ids) => Promise.all(ids.map(async (id) => ({ id, name: await fetchFullName(id) }))); const fetchImage = async (id) => { const res = await fetch( `https://nfl-api-data.p.rapidapi.com/nfl-ath-img?id=${encodeURIComponent(id)}`, { headers: { "x-rapidapi-key": "secret key", "x-rapidapi-host": "nfl-api-data.p.rapidapi.com", }, }, ); if (!res.ok) { throw new Error(`Image lookup for id '${id}' failed`); } return (await res.json()).image.href; }; const fetchImages = async (ids) => Promise.all(ids.map(async (id) => ({ id, image: await fetchImage(id) }))); export default function _quarterbacksPage() { const [players, setPlayers] = useState([]); useEffect(() => { const fetchPlayers = async () => { try { const [namesData, imagesData] = await Promise.all([ fetchFullNames(quarterbacks), fetchImages(quarterbacks) ]); const mergedPlayers = namesData.map(nameItem => { const imageMatch = imagesData.find(img => img.id === nameItem.id); return { ...nameItem, image: imageMatch ? imageMatch.image : '' }; }); setPlayers(mergedPlayers); } catch (err) { console.error(err); } }; fetchPlayers(); }, []); return ( <> <_navbar /> {players.map(({ id, name, image }) => ( <div className={styles.card} key={id}> {image && <img src={image} alt={`${name}的球员照片`} />} <Link className={styles.cardText} to={`/quarterback/${id}`}> {name} </Link> </div> ))} </> ); }
额外优化建议
- 使用
Promise.all并行发起请求,减少整体等待时间。 - 可为图片添加默认占位图,处理图片加载失败的情况。
- 完善
alt属性内容,提升页面可访问性。
内容的提问来源于stack exchange,提问作者Jace Johnson
相关产品推荐
相关产品推荐

