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

React电商项目中每2个ProductCard后渲染CompanyCard报错求助

问题描述

我正在开发一个电商商城,希望每渲染2个<ProductCard/>组件后,渲染一个<CompanyCard/>组件。期望的渲染顺序如下:

<ProductCard/>
<ProductCard/>
<CompanyCard/>
<ProductCard/>
<ProductCard/>
<CompanyCard/>
(and so on..)

但目前页面空白,控制台出现两个错误:

The above error occurred in the <CompanyCard> component:
Uncaught TypeError: Cannot read properties of undefined (reading '_id')

以下是我的代码(使用React Redux):

function HomePage() {
  let counter = 0;

  const dispatch = useDispatch();

  const productList = useSelector((state) => state.productList);
  const { error, loading, products } = productList;

  const companyList = useSelector((state) => state.companyList);
  const { companies } = companyList;

  useEffect(() => {
    dispatch(listProducts(), listCompanies());
  }, [dispatch]);

  return (
    <>
      <Navbar />
      <div className="homePage">
        <div className="centerItemsContainer">
          <div className="productsContainer">
            {products.map((product) => {
              counter++;

              if (counter % 4 === 0) {
                const companyIndex = counter / 4 - 1;
                const company = companies[companyIndex];

                return (
                  <>
                    <CompanyCard company={company} />
                    <ProductCard product={product} />
                  </>
                );
              } else {
                return <ProductCard product={product} />;
              }
            })}
          </div>
        </div>
      </div>
      <Footer />
    </>
  );
}

export default HomePage;
问题分析与修复

1. 核心错误原因

  • 商家数据未正确加载或索引越界:控制台报错说明传给<CompanyCard>的company是undefined,要么是listCompanies没触发,要么是商家数组长度不够导致索引找不到对应元素。
  • 计数器逻辑错误:在map里修改全局counter,组件重渲染时会重置,而且逻辑是每4个产品才插商家卡,和需求的“每2个产品后插商家卡”完全不符。
  • dispatch用法错误:dispatch一次只能传一个action,你写的dispatch(listProducts(), listCompanies())只会执行第一个,第二个直接被忽略。

2. 分步修复

先修正dispatch调用

把两个dispatch分开写,确保两个接口都触发:

useEffect(() => {
  dispatch(listProducts());
  dispatch(listCompanies());
}, [dispatch]);

重构渲染逻辑,实现正确顺序

放弃全局计数器,用数组索引来判断位置,同时处理边界情况避免报错:

function HomePage() {
  const dispatch = useDispatch();

  const productList = useSelector((state) => state.productList);
  const { error, loading, products } = productList;

  const companyList = useSelector((state) => state.companyList);
  const { companies } = companyList;

  useEffect(() => {
    dispatch(listProducts());
    dispatch(listCompanies());
  }, [dispatch]);

  // 处理加载、错误、无数据状态,避免页面空白
  if (loading) return <div>加载中...</div>;
  if (error) return <div>产品加载失败: {error}</div>;
  if (!companies || companies.length === 0) return <div>暂无商家信息</div>;

  // 构建最终渲染的元素数组
  const renderItems = [];
  products.forEach((product, index) => {
    // 先添加当前产品卡片
    renderItems.push(<ProductCard key={`product-${index}`} product={product} />);
    
    // 每2个产品后插入商家卡片(索引从0开始,所以用index+1判断)
    if ((index + 1) % 2 === 0) {
      // 计算商家索引,用取模循环使用商家数据,避免越界
      const companyIndex = Math.floor((index + 1) / 2) - 1;
      const targetCompany = companies[companyIndex % companies.length];
      if (targetCompany) {
        renderItems.push(<CompanyCard key={`company-${companyIndex}`} company={targetCompany} />);
      }
    }
  });

  return (
    <>
      <Navbar />
      <div className="homePage">
        <div className="centerItemsContainer">
          <div className="productsContainer">
            {renderItems}
          </div>
        </div>
      </div>
      <Footer />
    </>
  );
}

export default HomePage;

关键优化点

  • 用forEach构建渲染数组,比map更灵活处理“插入多个元素”的场景
  • 增加加载、错误状态提示,解决页面空白问题
  • 用companyIndex % companies.length循环复用商家数据,彻底避免索引越界
  • 给每个组件加唯一key,符合React列表渲染规范

3. 额外建议

  • 在<CompanyCard>组件里加容错逻辑,比如当company为undefined时显示默认占位内容,避免组件崩溃
  • 检查Redux中listCompanies的action和reducer,确保商家数据被正确存入store

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:25:17