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

React使用Context实现购物车时setState不生效如何解决?

问题修复方案

你现有代码的decreaseProduct方法存在4处核心错误,导致无法正确修改state:

  1. setState回调直接返回数组,没有指定要更新的productsToPurchase字段,React无法识别要修改的state属性
  2. 遍历productsToPurchase时,未匹配到对应itemId的商品没有返回值,会导致数组出现undefined元素
  3. 商品数量为1时仅打印日志,没有执行移除商品的逻辑
  4. 修改商品数量后没有同步更新总价totalPrice

修复后的类组件代码

import { createContext, Component } from 'react';

export const CartContext = createContext()

class CartContextProvider extends Component {
    state = {
        productsToPurchase: [],
        totalPrice:[]
    }

    addProduct = (itemId, prices) => {
        this.setState(oldState => {
            const objWithIdExist = oldState.productsToPurchase.find((o) => o.itemId === itemId);
            const newProducts = !objWithIdExist
                ? [...oldState.productsToPurchase, { itemId, qty: 1, price: prices }]
                : oldState.productsToPurchase.map((o) =>
                    o.itemId !== itemId ? o : { ...o, qty: o.qty + 1 }
                )
            return {
                productsToPurchase: newProducts,
                totalPrice: getTotalAmount(newProducts)
            }
        })
        // 合并两次setState操作,避免state异步更新导致的总价计算错误
    }

    decreaseProduct = (itemId) =>{
        this.setState(oldState=>{
            // 先处理数量减少/移除逻辑
            let newProducts = oldState.productsToPurchase.map(product=>{
                // 不匹配的商品直接返回原对象
                if (product.itemId !== itemId) return product
                // 匹配的商品处理数量
                if (product.qty === 1) {
                    // 标记需要移除
                    return null
                } else {
                    return {...product, qty: product.qty -1}
                }
            }).filter(Boolean) // 过滤掉标记为null的待移除商品

            return {
                productsToPurchase: newProducts,
                totalPrice: getTotalAmount(newProducts)
            }
        })
    }

    render() {
        return (
            <CartContext.Provider value={{...this.state, addProduct: this.addProduct, decreaseProduct: this.decreaseProduct}}>
                {this.props.children}
            </CartContext.Provider>
        )
    }
}

function getTotalAmount(productsToPurchase) {
    const totalPrice = []
    productsToPurchase.forEach((product) =>{
        product.price.forEach((price)=>{
            const existCurrency = totalPrice.find(t => t.currency === price.currency)
            if (existCurrency) {
                existCurrency.amount += price.amount * product.qty
            } else {
                totalPrice.push({currency: price.currency, amount: price.amount * product.qty})
            }
        })
    })
    // 优化了总价计算逻辑,原来的索引判断写法容错率低,现在直接判断币种是否存在即可
    return totalPrice
}

export default CartContextProvider;

函数式组件+useState实现版本

如果你需要改用函数组件调用useState实现,代码如下:

import { createContext, useState } from 'react';

export const CartContext = createContext()

const CartContextProvider = ({children}) => {
    const [productsToPurchase, setProductsToPurchase] = useState([])
    const [totalPrice, setTotalPrice] = useState([])

    const addProduct = (itemId, prices) => {
        setProductsToPurchase(old => {
            const objWithIdExist = old.find((o) => o.itemId === itemId);
            const newProducts = !objWithIdExist
                ? [...old, { itemId, qty: 1, price: prices }]
                : old.map((o) => o.itemId !== itemId ? o : { ...o, qty: o.qty + 1 })
            setTotalPrice(getTotalAmount(newProducts))
            return newProducts
        })
    }

    const decreaseProduct = (itemId) =>{
        setProductsToPurchase(old => {
            const newProducts = old.map(product=>{
                if (product.itemId !== itemId) return product
                return product.qty === 1 ? null : {...product, qty: product.qty -1}
            }).filter(Boolean)
            setTotalPrice(getTotalAmount(newProducts))
            return newProducts
        })
    }

    return (
        <CartContext.Provider value={{productsToPurchase, totalPrice, addProduct, decreaseProduct}}>
            {children}
        </CartContext.Provider>
    )
}

function getTotalAmount(productsToPurchase) {
    const totalPrice = []
    productsToPurchase.forEach((product) =>{
        product.price.forEach((price)=>{
            const existCurrency = totalPrice.find(t => t.currency === price.currency)
            if (existCurrency) {
                existCurrency.amount += price.amount * product.qty
            } else {
                totalPrice.push({currency: price.currency, amount: price.amount * product.qty})
            }
        })
    })
    return totalPrice
}

export default CartContextProvider;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 10:15:02