You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 05:24:23