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

React实现加入购物车按钮报buttonText未定义TypeError排查

报错根因

你触发的TypeError: Cannot set properties of undefined (setting 'buttonText')和按钮文案不更新问题,由3个代码逻辑错误直接导致:

  • 状态初始化时机错误:useState(props.products)仅在组件首次挂载时执行一次赋值。如果组件首次挂载时父组件还未完成fetch请求、传入的products是空数组/undefined,本地statebuttonText会永久保留初始空值,后续props更新不会自动同步到这个state中。点击事件触发时,你对空值做深拷贝得到的是空数组,访问testing[index]得到undefined,给undefined对象赋值属性就会抛出你看到的错误。
  • 渲染数据源错误:组件return中遍历渲染始终使用props.products,哪怕你正确更新了本地state,视图读取的还是props里的原始值,按钮文案永远不会变化。
  • 兜底逻辑无效:你写的const testing = newText || []仅在newText本身是null/undefined时才会兜底为空数组,如果newText是空数组(属于真值),兜底逻辑不会触发,此时访问数组的任意索引都会得到undefined。
可直接运行的修复代码
import React, { useState, useEffect } from "react";
import "../sass/layout/_grid.scss";
import "../sass/components/_product-card.scss";
import "../sass/components/_buttons.scss";

export interface ProductProps {
    products: {
        id: number;
        name: string;
        price: number;
        desc: string;
        img: string;
        units: number;
        buttonText: string;
    }[];
}

const ProductCard: React.FC<ProductProps> = (props) => {
    // 初始值加空数组兜底,避免首次挂载无数据时报错
    const [productList, setProductList] = useState(props.products || []);

    // 监听props变化,fetch完成拿到数据后自动同步到本地state
    useEffect(() => {
        setProductList(props.products || []);
    }, [props.products]);

    const handleClick = (index: number) => {
        // 用扩展运算符做浅拷贝,替代JSON序列化的低性能写法
        const newList = [...productList];
        // 操作前判断索引项是否存在,彻底避免数组越界
        if (newList[index]) {
            newList[index] = {
                ...newList[index],
                buttonText: "Adding to cart..."
            };
            setProductList(newList);
            
            setTimeout(() => {
                // 仅重置当前点击按钮的文案,不影响其他商品
                const resetList = [...newList];
                resetList[index] = {
                    ...resetList[index],
                    buttonText: "add to cart"
                };
                setProductList(resetList);
            }, 2000);
        }
    };

    return (
        <>
            {productList.length > 0 &&
                productList.map((it, index) => (
                    <article key={it.id} className="product-card">
                        <img src={it.img} alt={it.name} />
                        <h3>{it.name}</h3>
                        <p>{it.desc}</p>
                        <h4>{it.price}.00€</h4>
                        <div className="product-card__button--wrapper">
                            <button
                                className="product-card-button"
                                onClick={() => {
                                    handleClick(index);
                                    console.log(it.id);
                                }}
                            >
                                {it.buttonText}
                            </button>
                            <button className="product-card-button">info</button>
                        </div>
                    </article>
                ))}
        </>
    );
};

export default ProductCard;
关键修复点说明
  • 给state初始值增加空数组兜底,组件首次挂载哪怕props未传值也不会出现undefined异常
  • 新增useEffect监听props.products变化,fetch请求完成后自动同步数据到本地state,解决初始值为空导致的数组越界问题
  • 替换JSON深拷贝为扩展运算符浅拷贝,符合React状态更新规范,避免大列表下的性能损耗
  • 数组操作前增加索引项存在性判断,从根源上避免给undefined赋值的报错
  • 渲染时遍历本地state存储的商品列表,状态更新后按钮文案可以实时响应变化
  • 移除按钮上多余的key属性(key仅需加在遍历的最外层article元素上即可,内层子元素无需重复添加)
  • 定时器逻辑调整为仅重置当前点击按钮的文案,多商品点击时不会互相干扰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:30:52