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

React如何延迟页面渲染直到API数据返回,解决首次加载报错问题

问题原因
  • 你的初始化状态productData的值为null,React组件首次渲染会先执行return里的渲染逻辑,此时直接调用productData.variants.map等价于读取null.variants,会直接抛出类型错误。
  • useEffect的执行时机是组件首次渲染完成之后,所以API请求是在第一次渲染报错之后才发起的,等请求成功更新状态触发二次渲染时,才有值可以正常渲染,这也是你改代码触发热重载后功能正常的原因。
解决方案

你可以通过加空值判断/加载占位符的方式解决,不需要强行延迟页面渲染流程,体验更好:

方案1:添加加载态判断(推荐)

在数据返回前渲染加载提示/骨架屏,等数据加载完成再渲染实际内容,同时修正了你原代码中async/await和then混用、缺少尺寸状态定义等问题,修正后的完整代码如下:

import React, { useState, useEffect } from 'react'

export default function ProductPage({ data }) {
  const [productData, setProductData] = useState(null)
  // 补充你代码里缺失的尺寸选择相关状态
  const [activeSize, setActiveSize] = useState(null)

  useEffect(() => {
    getProductdata()
  }, [])

  async function getProductdata(){
    try {
      const secret = "SECRET"
      const response = await fetch(`https://app.myapi.com/api/products/${data.productsCsv.id}`, {
        headers: {
          'Authorization': `Basic ${btoa(secret)}`,
          'Accept': 'application/json'
        }
      })
      const result = await response.json()
      setProductData(result)
    } catch (err) {
      console.log(err)
    }
  }

  const toggleSize = (index) => {
    setActiveSize(index)
  }

  // 加载态判断,数据未返回时直接渲染加载提示
  if (!productData) return <div>加载中...</div>

  return (
    <>
      <div className="stock mb-4 ">
        <p className="tracking-wider mb-2">Size</p>
        {productData.variants.map((variant,index)=>{
          if(variant.stock != 0){
            return (
              <button className={`p-2 border-gray-200 border mr-2 mb-2 hover:bg-black hover:text-white cursor-pointer focus:border-black ${activeSize === index ? 'bg-black text-white' : ''}`} role="button" tabIndex={0} 
                onClick={() => toggleSize(index)}
                onKeyDown={() => toggleSize(index)} key={index}>{variant.variation[0].option}-{variant.stock}</button>
            )
          } else {
            return(
              <button className={`p-2 border-gray-200 border mr-2 mb-2 ${variant.stock == 0 ?'bg-gray-400 line-through text-red-500': ''}`} disabled role="button" tabIndex={0} 
                onClick={() => toggleSize(index)}
                onKeyDown={() => toggleSize(index)} key={index}>{variant.variation[0].option}-{variant.stock}</button>
            )
          }
        })} 
      </div>
    </>
  )
}

方案2:可选链兼容

如果不需要显示加载态,也可以用可选链运算符避免空值报错,写法如下:

{productData?.variants?.map((variant,index)=>{
  // 原有渲染逻辑
})}

这种方式不会抛出错误,但数据加载完成前对应区域是空的,用户体验不如加载态友好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 21:54:04