React Context API下useState存储的Cart数组触发onClick事件不更新问题
问题原因
1. 产品页组件状态未和Context同步
你产品列表的父组件应该是直接遍历了初始的storeProducts静态数据,将每个产品作为props传给Product组件,而非从Context中读取products.product数组渲染。这就导致Context中产品的inCart属性更新后,props传入的产品数据还是初始值,按钮状态不会变化,看起来加购逻辑失效。而详情页的inCart是直接从Context读取的detailsProduct,能实时拿到最新状态,所以逻辑正常。
2. 状态更新存在闭包陷阱
你所有调用setProducts的地方,都是直接展开当前作用域的products对象,这个products是当前渲染闭包捕获的旧状态值,多次状态更新时会出现更新丢失,比如cart数组没有正确追加新商品。
修复方案
第一步:修改产品列表父组件的渲染逻辑
不要直接用外部的storeProducts遍历,改为从Context中读取产品数组渲染:
// 产品列表组件示例 import React from 'react'; import Product from './Product'; import { ConsumerContext } from '../Context'; const ProductList = () => { return ( <ConsumerContext> {value => value.product.map(item => <Product key={item.id} product={item} />)} </ConsumerContext> ) }
这样Context中产品数据更新时,会重新渲染所有商品项,props传入的product就是最新值。
第二步:修改Context的状态更新为函数式更新
所有调用setProducts的地方都改为用函数式更新,从参数中拿到最新的前序状态,避免闭包问题,同时修改对象时先复制再更新,不要直接修改原状态引用:
// 修改addToCart方法 const addToCart = (id) => { setProducts(prev => { const tempProducts = [...prev.product]; const index = tempProducts.findIndex(item => item.id === id); // 复制对象再修改,避免直接修改原状态 const cartProduct = {...tempProducts[index]}; cartProduct.inCart = true; cartProduct.count = 1; cartProduct.total = cartProduct.price; tempProducts[index] = cartProduct; return { ...prev, product: tempProducts, cart: [...prev.cart, cartProduct] } }) } // 修改newProducts方法 const newProducts = () => { let tempProducts = []; storeProducts.forEach((item) => { const singleItem = { ...item }; tempProducts = [...tempProducts, singleItem]; }); setProducts(prev => ({ ...prev, product: tempProducts, })); }; // 其他方法比如handleDetail、openModal、closeModal都同理修改,比如: const handleDetail = (id) => { setProducts(prev => { const newProduct = prev.product.find(item => item.id === id); return { ...prev, detailsProduct: newProduct } }) }
内容的提问来源于stack exchange,提问作者Babadinho
相关产品推荐
相关产品推荐

