React使用Context实现购物车时setState不生效如何解决?
问题修复方案
你现有代码的decreaseProduct方法存在4处核心错误,导致无法正确修改state:
setState回调直接返回数组,没有指定要更新的productsToPurchase字段,React无法识别要修改的state属性- 遍历
productsToPurchase时,未匹配到对应itemId的商品没有返回值,会导致数组出现undefined元素 - 商品数量为1时仅打印日志,没有执行移除商品的逻辑
- 修改商品数量后没有同步更新总价
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
相关产品推荐
相关产品推荐

