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

React中fetch调用API获取万智牌数据渲染不一致问题求助

问题分析与解决方案

核心问题

  1. 异步处理逻辑错误:用forEach循环执行异步fetch请求时,forEach不会等待异步操作完成,导致每个请求返回后立刻更新状态,造成状态分批次更新,渲染时只能显示当前已返回的卡牌。同时直接修改objects数组(objects.push(result)),没有创建新数组,React可能无法检测到状态变化。
  2. 渲染代码错误:每个条件分支都复用scrydata[0]的图片地址和key,导致即使数组有多个元素,显示的都是第一张卡牌的重复内容,手动写7个条件也容易出错。
  3. Promise.all使用不当:你错误地将单个response.json()包装进Promise.all,这完全无效,正确做法是把所有fetch请求的Promise收集起来,用Promise.all等待全部完成。

修复后的代码

1. 修正异步请求逻辑

const handleClick = async () => {
  // 分割卡牌列表并过滤空行,避免无效请求
  const cardNames = textarea.split("\n").filter(name => name.trim());
  // 限制最多7张卡牌
  const limitedNames = cardNames.slice(0, 7);

  try {
    setIsLoading(true);
    // 生成所有fetch请求的Promise数组
    const cardPromises = limitedNames.map(async (name) => {
      const response = await fetch(
        `https://api.scryfall.com/cards/named?exact=${encodeURIComponent(name.trim())}`
      );
      if (!response.ok) {
        throw new Error(`获取卡牌失败: ${response.status}`);
      }
      return await response.json();
    });

    // 等待所有请求完成,拿到全部卡牌数据
    const allCards = await Promise.all(cardPromises);
    // 打乱顺序(如果需要)
    const shuffledCards = [...allCards].sort(() => Math.random() - 0.5);
    // 一次性更新状态
    setScrydata(shuffledCards);
  } catch (err) {
    console.error(err);
  } finally {
    setIsLoading(false);
  }
};

2. 修正渲染逻辑

{scrydata.length > 0 && scrydata.map((card) => (
  <img
    key={card.id}
    src={card.image_uris?.normal}
    alt={card.name}
    loading="lazy" // 可选,优化图片加载性能
  />
))}

关键改进点

  • 批量异步处理:用Promise.all等待所有请求完成后再更新状态,确保一次渲染所有卡牌。
  • 不可变状态更新:创建新数组([...allCards])而非修改原数组,保证React能检测到状态变化。
  • 简洁渲染:用map循环替代重复的条件判断,自动渲染所有已获取的卡牌,且每个元素使用唯一的card.id作为key。
  • 过滤空行:避免空字符串导致的无效API请求。
  • 数量限制:提前截取最多7张卡牌,符合需求。

内容的提问来源于stack exchange,提问作者Robert Angberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 20:40:31