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

React加密货币应用:API数据可打印但无法渲染,map函数报错

问题分析与解决

问题现象

使用React开发加密货币应用时调用免费API获取数据,遇到以下问题:

  • Axios请求后,console.log(response.data)能看到返回的数组,但执行setCoinList(response.data.coins)时,报错Uncaught TypeError: coinList.map is not a function
  • 初始状态设为空数组,编辑器无语法错误,Coin组件运行正常
  • 添加coinList &&判断后,报错消失,但页面无内容显示,且控制台数组会被打印两次

原代码

function App() {
  const [coinList, setCoinList] = useState([]);
  useEffect(() => {
    const options = {
      method: "GET",
      url: "https://openapiv1.coinstats.app/coins",
      params: { limit: "20" },
      headers: {
        accept: "application/json",
        "X-API-KEY": MYAPIKEYHERE,
      },
    };
    axios
      .request(options)
      .then((response) => {
        setCoinList(response.data.coins);
      })
      .catch((error) => {
        console.error(error);
      });
  }, []);
  return (
    <div className="container mx-auto mt-8">
      {coinList.map((coin) => {
        return (
          <Coin
            key={coin.rank}
            name={coin.name}
            icon={coin.icon}
            symbol={coin.symbol}
            volume={coin.volume}
            price={coin.price}
          />
        );
      })}
    </div>
  );
}

修改后的代码片段

<div className="container mx-auto mt-8">
  {coinList && coinList.map((coin) => {
    return (
      <Coin
        key={coin.rank}
        name={coin.name}
        icon={coin.icon}
        symbol={coin.symbol}
        volume={coin.volume}
        price={coin.price}
      />
    );
  })}
</div>

原因分析

  1. map is not a function报错:核心原因是coinList不是数组。虽然初始状态是空数组,但请求返回后,response.data.coins可能并非数组——比如API返回的data本身就是数组,不需要额外取coins字段;或者coins字段为null/undefined。
  2. 页面无内容:添加coinList &&后,若coinList是空数组,&&判断为真但map遍历空数组不会生成任何元素;若response.data.coins是undefined,coinList会被设为undefined,此时coinList &&为假,不会执行map。
  3. 控制台打印两次:开发环境下React严格模式会触发两次组件渲染和useEffect执行,属于正常现象,生产环境不会出现。

解决方案

  1. 确认API返回结构:在then回调里打印完整的response.data,确认coins字段是否存在且为数组,再针对性赋值:
    .then((response) => {
      console.log('API返回数据:', response.data);
      // 若API返回的data直接是数组,无需取coins字段
      // setCoinList(response.data);
      // 若存在coins字段,先判断是否为数组再赋值
      if (Array.isArray(response.data.coins)) {
        setCoinList(response.data.coins);
      } else {
        console.warn('返回的coins不是数组:', response.data.coins);
      }
    })
    
  2. 更严谨的数组判断:将coinList &&替换为Array.isArray(coinList),避免非数组类型导致的逻辑问题:
    {Array.isArray(coinList) && coinList.map((coin) => (
      <Coin
        key={coin.rank}
        name={coin.name}
        icon={coin.icon}
        symbol={coin.symbol}
        volume={coin.volume}
        price={coin.price}
      />
    ))}
    
  3. 添加加载状态:提升用户体验,在数据未加载完成时显示加载提示:
    const [isLoading, setIsLoading] = useState(true);
    // 在useEffect的then和catch回调中都设置setIsLoading(false)
    useEffect(() => {
      // ... 原有请求代码
      axios.request(options)
        .then((response) => {
          // ... 赋值逻辑
          setIsLoading(false);
        })
        .catch((error) => {
          console.error(error);
          setIsLoading(false);
        });
    }, []);
    
    return (
      <div className="container mx-auto mt-8">
        {isLoading ? <div>加载中...</div> : (
          Array.isArray(coinList) && coinList.map((coin) => (
            <Coin {...coin} key={coin.rank} />
          ))
        )}
      </div>
    )
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:45:22