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

React Hooks 场景下向state数组推入对象功能实现异常问题咨询

问题核心原因

  • 组件不能声明为async函数,React不支持异步组件直接导出,会导致渲染异常
  • useState未给初始值,productData初始状态为undefined,第一次更新时判空逻辑直接失效
  • 异步遍历用了forEach,forEach不会等待异步回调执行完成,且回调中拿到的productData永远是第一次渲染的快照值,无法获取最新的状态
  • 每次更新状态后你又额外执行了一次setProductData([单个产品对象]),直接覆盖了之前累加的结果
  • 渲染时直接访问productData[0],未做非空判断,初始加载时会直接抛出类型错误

修复方案

调整状态初始化、异步遍历逻辑、状态更新方式后的可运行代码如下:

import { useState, useEffect } from 'react';

export const Component = () => {
  const productPages = ["testURL", "testURL", "testURL", "testURL"];
  // 给状态设置初始空数组
  const [productData, setProductData] = useState([]);

  useEffect(() => {
    const getData = async urls => {
      // 用for of代替forEach,保证异步操作按顺序执行
      for (const url of urls) {
        try {
          const response = await fetch(url);
          const html = await response.text();
          const productPage = document.createElement("div");
          productPage.classList.add("hidden");
          productPage.id = "no-visual";
          productPage.innerHTML = html;

          productPage
            .querySelector('[data-test-id="main-price"]')
            .firstChild.remove();
          productPage
            .querySelector('[data-test-id="main-price"]')
            .lastChild.remove();
          productPage
            .querySelector('[data-test-id="second-price"]')
            .firstChild.remove();
          productPage
            .querySelector('[data-test-id="second-price"]')
            .lastChild.remove();

          const productName = productPage.querySelector(
            '[data-test-id="product-name"] h1'
          ).textContent;
          const productMainPrice = productPage.querySelector(
            '[data-test-id="main-price"]'
          ).textContent;
          const productSecondPrice = productPage.querySelector(
            '[data-test-id="second-price"]'
          ).textContent;
          const productQuantity = productPage.querySelector(
            '[data-test-id="button-wrapper"]'
          ).outerHTML;
          const productAddToBag = productPage.querySelector(
            '[data-test-id="button-wrapper"]'
          ).nextElementSibling.outerHTML;
          
          // 用函数式更新,获取最新的状态值,避免快照问题
          setProductData(prev => [
            ...prev,
            {
              productName,
              productMainPrice,
              productSecondPrice,
              productQuantity,
              productAddToBag
            }
          ]);
        } catch (err) {
          // 增加错误捕获,避免单个请求失败导致整个流程崩溃
          console.error('页面请求失败', url, err);
        }
      }
    };
    getData(productPages);
  }, []);

  // 渲染前增加非空判断,避免初始加载报错
  if (!productData.length) return <div>加载中...</div>;

  return (
    <div className="grid2x2">
      <div className="box box1">
        <div>
          <img src="" alt="" />
        </div>
        <div>
          <div>
            {productData[0].productName} {productData[0].productMainPrice}
            <span> EX VAT </span> {productData[0].productSecondPrice}
            {productData[0].productQuantity} {productData[0].productAddToBag}
            <span> INC VAT </span>
          </div>
        </div>
      </div>
    </div>
  );
};

优化提示

如果需要提高请求效率,可以用Promise.all包裹所有请求,等所有请求返回后再一次性更新状态,减少重渲染次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 08:24:03