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

React useEffect发起axios请求首次返回空数组致取值报错

问题原因
  • useEffect的执行时机是组件首次挂载渲染完成后,内部的axios异步请求存在网络耗时,因此Hook首次返回的products永远是useState初始化的空数组[],等接口响应完成后才会更新为真实数据
  • 渲染时未做任何边界判断:如果接口返回数据结构不符合预期、数组遍历过程中取到了不存在的对象属性,就会拿到undefined值,直接传入组件渲染时触发报错,报错示例如下:
    undefined取值报错截图
  • 原Hook还存在两个隐性问题:useEffect依赖数组为空,传入的API地址变更时不会重新发起请求;未做组件卸载时的请求状态处理,容易触发内存泄漏警告。
修复方案

第一步:优化自定义Hook逻辑

补充加载状态、错误兜底、数据格式校验、依赖修正以及卸载保护,代码如下:

const useGetProducts = (API) => {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let isUnmounted = false;
    setLoading(true);

    async function fetchData() {
      try {
        const response = await axios(API);
        if (!isUnmounted) {
          // 强制兜底为数组格式,避免接口返回非数组结构导致后续遍历报错
          setProducts(Array.isArray(response.data) ? response.data : []);
          setError(null);
        }
      } catch (err) {
        if (!isUnmounted) {
          setError(err);
          setProducts([]);
        }
      } finally {
        if (!isUnmounted) {
          setLoading(false);
        }
      }
    }

    fetchData();
    // 组件卸载时标记,避免更新已卸载组件的状态
    return () => {
      isUnmounted = true;
    };
  }, [API]); // 补全API依赖,地址变更时自动重新拉取数据

  return { products, loading, error };
};

第二步:渲染层增加边界判断

不要拿到Hook返回值直接渲染,根据加载、错误、空数据状态分别做兜底处理:

// 业务组件中使用Hook
const { products, loading, error } = useGetProducts("/api/products");

// 加载中兜底
if (loading) return <div>商品列表加载中...</div>;
// 请求错误兜底
if (error) return <div>加载失败,请刷新页面重试</div>;

return (
  <div className="product-container">
    {/* 校验数组有效后再遍历 */}
    {products.length > 0 &&
      products.map((product) => {
        // 过滤数组中的无效空项
        if (!product) return null;
        return <ProductItem key={product.id} product={product} />;
      })}
    {/* 空列表兜底 */}
    {products.length === 0 && <div>暂无相关商品</div>}
  </div>
);

可选优化项

  • 如果ProductItem组件内部存在深层属性取值(比如product.shop.logo这类链式取值),统一使用可选链操作符product?.shop?.logo做兜底,避免中间属性不存在触发报错
  • 列表渲染必须传入唯一key值,禁止直接使用数组下标作为key,防止列表动态更新时出现渲染错位问题
  • 如果接口请求耗时较长,可以在Hook中加入AbortController主动中断未完成的请求,进一步优化性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:33:43