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

为API获取的数组对象添加isAdded后点击按钮时该值显示undefined求助

问题描述

从API获取商品数据后,通过forEach循环给商品数组里的每个对象添加isAdded键并设初始值为false,商品添加到<Cart />组件的功能正常,但点击“Add to cart”按钮时,isAdded值显示undefined,无法实现按钮文本和样式的切换。


相关代码

BookProduct.js

import BookItems from "./BookItems";
import classes from "./book-item.module.css";
import { useEffect } from "react";

export default function BookProducts({ booksData }) {
    useEffect(() => {
        booksData.forEach((element) => {
            element.isAdded = false;
        });
    }, []);

    console.log(booksData); // isAdded键已成功添加到对象中

    return (
        <div className="container">         
                {booksData.map((el) => {
                    return (
                        <BookItems
                            id={el.isbn13}
                            key={el.isbn13}
                            imageUrl={el.image}
                            price={Number(el.price.slice(1))}
                            title={el.title}
                            subtitle={el.subtitle}
                            link={el.link}
                            isAdded={el.isAdded}
                        />
                    );
                })}     
        </div>
    );
}

BookItems.js

import { useDispatch, useSelector } from "react-redux";
import Image from "next/image";
import Link from "next/link";
import classes from "./book-item.module.css";
import { cartStoreAction } from "../../store/cart-items";

export default function BookItems(props) {
    const { id, title, price, imageUrl, isAdded } = props;
    const dispatch = useDispatch();

    const addToCartHandler = () => {
        dispatch(
            cartStoreAction.addProduct({
                id,
                title,
                price,
                imageUrl,
                isAdded
            })
        );
        console.log(isAdded); // 此处isAdded显示undefined
    };

    return (
        <div className={classes.product__item}>
            <Link href={`/products/${id}`} className={classes.image_box}>
                <Image src={imageUrl} alt={title} className={classes.image} fill />
            </Link>
            <div className={classes.desc_box}>
                <Link href={`/products/${id}`}>
                    <h3>{title}</h3>
                </Link>
                <div className={classes.bottom}>
                    <p>${price}</p>
                    <button onClick={addToCartHandler}>
                        {isAdded ? '已添加' : '加入购物车'}
                    </button>
                </div>
            </div>
        </div>
    );
}

cart-items.js

const cartItemSlice = createSlice({
    name: "cart",
    initialState: {
        items: [],
        totalQuantity: 0,
        totalAmount: 0,
    },
    reducers: {
        addProduct(state, action) {
            const newCartItems = action.payload; // 来自dispatch的对象
            const existingItem = state.items.find((el) => el.id === newCartItems.id);                   
            state.totalQuantity++;
            if (!existingItem) {
                state.items.push({
                    id: newCartItems.id,
                    quantity: 1,
                    title: newCartItems.title,
                    price: newCartItems.price,
                    image: newCartItems.imageUrl,
                    totalPrice: newCartItems.price,     
                    isAdded: !newCartItems.isAdded,
                });
                !newCartItems.isAdded;
            } else {
                existingItem.quantity++;
                existingItem.totalPrice = existingItem.totalPrice + newCartItems.price;
            }
            state.totalAmount = state.items.reduce(
                (acc, index) => acc + Number(index.price) * Number(index.quantity),
                0
            );
        },      
    },
});

问题原因及修复方案

核心问题

  1. 渲染时机不匹配:useEffect在组件首次渲染后执行,第一次渲染BookItems时,el.isAdded还未被添加,导致props.isAdded为undefined;后续即使修改了booksData,也没有触发组件重渲染,BookItems接收的isAdded始终是初始的undefined。
  2. props修改反模式:直接修改传入的booksData(props)不符合React规范,props是只读的,修改不会触发重渲染。
  3. 无效状态更新逻辑:Redux reducer里的!newCartItems.isAdded;是无效语句,无法同步更新组件的isAdded状态。

修复步骤

步骤1:用本地state管理商品数据

在BookProducts中将booksData转为本地state,确保添加isAdded后触发重渲染:

import BookItems from "./BookItems";
import classes from "./book-item.module.css";
import { useEffect, useState } from "react";

export default function BookProducts({ booksData }) {
    const [products, setProducts] = useState([]);

    useEffect(() => {
        // 创建新数组,不修改原props,给每个商品添加isAdded初始值
        const updatedProducts = booksData.map(element => ({
            ...element,
            isAdded: false
        }));
        setProducts(updatedProducts);
    }, [booksData]); // 依赖booksData,数据更新时重新处理

    return (
        <div className="container">         
                {products.map((el) => {
                    return (
                        <BookItems
                            id={el.isbn13}
                            key={el.isbn13}
                            imageUrl={el.image}
                            price={Number(el.price.slice(1))}
                            title={el.title}
                            subtitle={el.subtitle}
                            link={el.link}
                            isAdded={el.isAdded}
                            // 添加更新isAdded的回调函数
                            updateIsAdded={(id) => {
                                setProducts(prev => prev.map(item => 
                                    item.isbn13 === id ? {...item, isAdded: !item.isAdded} : item
                                ));
                            }}
                        />
                    );
                })}     
        </div>
    );
}

步骤2:修改BookItems组件,调用回调更新状态

import { useDispatch } from "react-redux";
import Image from "next/image";
import Link from "next/link";
import classes from "./book-item.module.css";
import { cartStoreAction } from "../../store/cart-items";

export default function BookItems(props) {
    const { id, title, price, imageUrl, isAdded, updateIsAdded } = props;
    const dispatch = useDispatch();

    const addToCartHandler = () => {
        dispatch(
            cartStoreAction.addProduct({
                id,
                title,
                price,
                imageUrl,
                isAdded: !isAdded // 传递切换后的值到Redux
            })
        );
        // 调用父组件回调更新本地isAdded状态
        updateIsAdded(id);
    };

    return (
        <div className={classes.product__item}>
            <Link href={`/products/${id}`} className={classes.image_box}>
                <Image src={imageUrl} alt={title} className={classes.image} fill />
            </Link>
            <div className={classes.desc_box}>
                <Link href={`/products/${id}`}>
                    <h3>{title}</h3>
                </Link>
                <div className={classes.bottom}>
                    <p>${price}</p>
                    <button onClick={addToCartHandler}>
                        {isAdded ? '已添加' : '加入购物车'}
                    </button>
                </div>
            </div>
        </div>
    );
}

步骤3:清理Redux reducer无效代码

移除reducer里的无效语句,且购物车状态无需存储isAdded(按钮状态属于组件本地UI状态):

const cartItemSlice = createSlice({
    name: "cart",
    initialState: {
        items: [],
        totalQuantity: 0,
        totalAmount: 0,
    },
    reducers: {
        addProduct(state, action) {
            const newCartItems = action.payload;
            const existingItem = state.items.find((el) => el.id === newCartItems.id);                   
            state.totalQuantity++;
            if (!existingItem) {
                state.items.push({
                    id: newCartItems.id,
                    quantity: 1,
                    title: newCartItems.title,
                    price: newCartItems.price,
                    image: newCartItems.imageUrl,
                    totalPrice: newCartItems.price,
                });
            } else {
                existingItem.quantity++;
                existingItem.totalPrice = existingItem.totalPrice + newCartItems.price;
            }
            state.totalAmount = state.items.reduce(
                (acc, index) => acc + Number(index.price) * Number(index.quantity),
                0
            );
        },      
    },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:10:34