React类组件setState无法更新state嵌套对象问题求助
问题根因
数量更新失效、展示异常是4个核心代码错误导致的:
- 跨组件传值缺失、参数引用错误:App中定义的
IncrementItem、DecrementItem方法需要接收商品id作为入参,但路由渲染Cart组件时没有把这两个方法透传下去,Cart根本调用不到父组件的更新方法;同时Cart里调用方法时写的id、products.id都是未定义的变量,拿不到当前循环项的商品id,参数传空自然没法匹配对应商品更新。 - Store组件加购事件绑定错误:Store循环商品列表时,onClick绑定的是
this.props.countId(小写开头),但App传给Store的方法是大写开头的CountId,事件本身就触发不了;就算绑定对了,之前写的中间层countId方法也没把事件对象透传回App,App拿不到挂载在dom上的商品id,加购逻辑跑不通,还会出现同个商品重复加购的问题。 - state更新逻辑有问题:最早用lodash写的增量逻辑完全不成立,
deepIncrement.map(i => i.id)返回的是所有id组成的字符串数组,数组本身没有quantity属性;后续改的find+filter版本会把每次更新的商品插到数组头部,多次操作后同个商品会在数组里重复出现,state结构直接混乱。 - Cart渲染逻辑错误:代码里写的
value.state.countId是不存在的变量,Cart作为类组件要从this.props取父组件传入的购物车数据;而且之前的map写法是把所有商品的数量全遍历出来堆在每个商品下面,没有按商品id做匹配,展示自然错乱。
修正方案
1. 修复App组件:补全传参、修正更新逻辑、加购去重
补全Cart组件的props传值,修复加购逻辑避免重复添加商品,用map做不可变更新,不打乱数组顺序,同时限制商品最低数量为1,不会减成负数:
class App extends Component { constructor(props) { super(props); this.state = { countId:{quantityId:[]}, }; } CountId = (event) => { const productId = event.currentTarget.id; // 同个商品重复点击不重复加购 const existItem = this.state.countId.quantityId.find(item => item.id === productId); if (existItem) return; this.setState({ countId:{ ...this.state.countId, quantityId: this.state.countId.quantityId.concat({id: productId, quantity: 1}) } }) } IncrementItem = (id) => { this.setState({ countId: { ...this.state.countId, quantityId: this.state.countId.quantityId.map(item => item.id === id ? {...item, quantity: item.quantity + 1} : item ) } }) } DecrementItem = (id) => { this.setState({ countId: { ...this.state.countId, quantityId: this.state.countId.quantityId.map(item => item.id === id ? {...item, quantity: Math.max(1, item.quantity - 1)} : item ) } }) } render() { return ( <div> <BrowserRouter> <Routes> <Route path='/store' element={<Store CountId={this.CountId}/>}/> <Route path='/cart' element={ <Cart countId={this.state.countId} IncrementItem={this.IncrementItem} DecrementItem={this.DecrementItem} /> }/> </Routes> </BrowserRouter> </div> ) } }
2. 修复Store组件:正确绑定加购事件
去掉多余的中间方法,直接绑定父组件传入的加购方法,给循环项加key避免渲染警告:
export default class Store extends Component { constructor(props) { super(props); this.state = { products: [ {id: "apple"}, {id: "lemon"}, {id: "melon"} ] }; } render() { return ( <div> {this.state.products.map((p) => { return ( <div key={p.id} id={p.id} onClick={this.props.CountId}> 加入购物车:{p.id} </div> ); })} </div> ); } }
3. 修复Cart组件:正确传参、按商品id匹配渲染数量
从props解构出需要的方法和数据,循环商品时匹配对应购物车条目,点击按钮时传入当前商品id,未加购的商品不在购物车展示:
export default class Cart extends Component { constructor(props) { super(props); this.state = { products: [ {id: "apple"}, {id: "lemon"}, {id: "melon"} ] }; } render() { const { countId, IncrementItem, DecrementItem } = this.props; return ( <div> {this.state.products.map((p) => { const cartItem = countId.quantityId.find(item => item.id === p.id); if (!cartItem) return null; return ( <div key={p.id}> <span>商品:{p.id}</span> <button onClick={() => IncrementItem(p.id)}>+</button> <div>{cartItem.quantity}</div> <button onClick={() => DecrementItem(p.id)}>-</button> </div> ); })} </div> ); } }
验证点
改完后可按流程验证:
- 进入/store页面点击商品,同个商品不会重复加入购物车
- 进入/cart页面只展示已加购的商品,点击+/-按钮只会修改对应商品的数量,不会串商品
- 商品数量最低为1,不会出现0或者负数
内容的提问来源于stack exchange,提问作者Nord
相关产品推荐
相关产品推荐

