React点击元素时动态设置CardMedia src为API返回图片链接问题
问题根因
你遇到的报错来自两个核心问题:
- 接口请求是异步行为,组件首次渲染时
kittenPicture还是初始值空数组,直接访问kittenPicture[0]会取到undefined,再读取largeImageURL属性就会抛出类型错误 - 直接遍历数组渲染会输出所有图片,固定取数组下标既没有解决空数据报错,也无法实现随机切换单张图片的需求
实现步骤
- 新增独立状态存储当前展示的单张猫咪图片地址,避免直接操作原始图片列表
- 移除写在组件顶层的
kittenPicture.map遍历打印逻辑,这类副作用逻辑不能直接放在函数组件渲染主流程中 - 在图片接口请求完成后,先校验返回的图片列表非空,再生成随机数组下标,选取单张图片地址存入新增的状态中
- 给图片地址加空值兜底,配合加载状态彻底解决初始化阶段的报错问题
完整修改后代码
import * as React from 'react'; import { useState, useEffect } from "react"; import { getFact } from "./api/fact"; import { getKittenPictures } from "./api/kittenPictures"; import Container from '@mui/material/Container'; import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import CardMedia from '@mui/material/CardMedia'; import Typography from '@mui/material/Typography'; import { CardActionArea, CircularProgress, Box } from '@mui/material'; function App() { const [fact, setFact] = useState(''); const [newFact, setNewFact] = useState(0); const [currentKittenImg, setCurrentKittenImg] = useState(''); const [loading, setLoading] = useState(true); useEffect(() => { setLoading(true); getFact().then((data) => setFact(data.fact)); getKittenPictures().then((data) => { const imgList = data.hits; if (imgList?.length > 0) { // 生成0到数组长度-1的随机下标 const randomIndex = Math.floor(Math.random() * imgList.length); setCurrentKittenImg(imgList[randomIndex].largeImageURL); } setLoading(false); }); }, [newFact]); const onNewFactHandler = () => { setNewFact(newFact + 1); }; return ( <React.Fragment> <Container maxWidth="lg"> <Card md={{ maxWidth: 345 }}> <CardActionArea onClick={onNewFactHandler}> {loading ? ( <Box sx={{ height: 300, display: 'flex', alignItems: 'center', justifyContent: 'center' }}> <CircularProgress /> </Box> ) : ( <CardMedia component="img" sx={{ height: 300, objectFit: 'cover' }} src={currentKittenImg} alt="Cute kitten" /> )} <CardContent> <Typography gutterBottom variant="h4" component="div">Random cat fact</Typography> <Typography variant="body1" color="black">{fact}</Typography> </CardContent> </CardActionArea> </Card> </Container> </React.Fragment> ); } export default App;
关键逻辑说明
- 随机数生成逻辑
Math.floor(Math.random() * imgList.length)可以保证每次请求完图片列表后,随机选中其中一张,不会固定取某一项 - 用可选链
imgList?.length做非空判断,避免接口返回异常、空数组场景下的报错 - 新增了简单的加载状态,接口请求过程中显示加载动画,避免空白图片的糟糕体验
- 移除了多余的
kittenPicture状态,不需要存储全量图片列表,拿到数据后直接选好需要的单张地址即可,减少无用状态维护 - 修正了
fact的初始值类型,原来初始化为数组不符合接口返回的字符串类型,改为空字符串避免类型异常
内容的提问来源于stack exchange,提问作者Alex Iglesias
相关产品推荐
相关产品推荐

