React更新嵌套数组对象值时保留其他属性的方法
React购物车多属性更新问题修复
问题描述
开发React购物车功能时,现有属性更新逻辑仅支持全量替换已选属性,无法实现修改单属性时保留其余已选属性的需求:例如原已选属性为「颜色:白色、尺码:M」,将尺码修改为L后,预期结果为「颜色:白色、尺码:L」,现有逻辑会丢失未修改的颜色属性。
现有代码
State定义
this.state = { cartItems: [], selectedAttributes: [] }
购物车商品数据结构
{ "__typename": "Product", "name": "iPhone 12 Pro", "inStock": true, "attributes": [ { "__typename": "AttributeSet", "id": "Capacity", "name": "Capacity", "type": "text", "items": [ { "__typename": "Attribute", "id": "512G", "value": "512G" }, { "__typename": "Attribute", "id": "1T", "value": "1T" } ] }, { "__typename": "AttributeSet", "id": "Color", "items": [ { "__typename": "Attribute", "id": "Black", "value": "#000000" }, { "__typename": "Attribute", "id": "White", "value": "#FFFFFF" } ] } ], "id": "product1", "quantity": 1, "selectedAttributes": [ { "value": "512G", "type": "Capacity", "id": "product1" }, { "value": "#44FF03", "type": "Color", "id": "product1" } ] }
原有问题逻辑
// 原有购物车更新函数(逻辑存在问题) updateCartItem = (cart, product, selectedAttribute, newAttributes) => { const existingCartItem = cart.find( (cartItem) => cartItem.id === product.id ); const thisCart = cart.filter((cartItem) => cartItem.id !== product.id) if (existingCartItem) { cart.map((cartItem) => cartItem.selectedAttributes.map((attr)=> attr.type===selectedAttribute.map((newAttr)=>newAttr.type ? newAttributes= [{ ...attr, value: newAttr.value, }] : [newAttributes = attr] ))); return [ ...thisCart, { ...product, selectedAttributes: newAttributes }, ]; } }; // 原有状态更新函数 updateItemToCart = (product, selectedAttributes) => { this.setState({ cartItems: this.updateCartItem(this.state.cartItems, product, selectedAttributes), }); }; // 已选属性处理函数 selectAttribute = (attribute, newAttribute, type, id) => { const existingAttribute = attribute.find( (attr) => attr.type === type && attr.id === id ); if (existingAttribute) { return attribute.map((attr) => attr.type === type && attr.id === id ? { ...attr, value: newAttribute } : attr ); } return [...attribute, { value: newAttribute, type, id }]; }; selectedAttributesHandler = (newAttribute, type, id) => { this.setState({ selectedAttributes: this.selectAttribute( this.state.selectedAttributes, newAttribute, type, id ), }); };
修复方案
原有updateCartItem存在三个核心问题:
- 嵌套map无返回值,属于无效逻辑
- 直接对入参变量赋值,存在副作用
- 全量替换
selectedAttributes,导致未修改的属性丢失
直接替换为以下逻辑即可实现需求:
修正后的updateCartItem函数
updateCartItem = (cart, product, attrType, newAttrValue) => { return cart.map(cartItem => { // 非目标商品直接返回原数据,不做修改 if (cartItem.id !== product.id) return cartItem; // 遍历更新目标商品的已选属性 const updatedAttributes = cartItem.selectedAttributes.map(attr => { // 匹配到当前要修改的属性类型,替换为新值 if (attr.type === attrType) { return { ...attr, value: newAttrValue }; } // 其余属性原样保留 return attr; }); // 兼容首次选择属性的场景:如果该类型属性不存在则追加 const attrExist = updatedAttributes.some(attr => attr.type === attrType); if (!attrExist) { updatedAttributes.push({ value: newAttrValue, type: attrType, id: product.id }); } // 返回更新后的商品数据 return { ...cartItem, selectedAttributes: updatedAttributes }; }); };
配套调整状态更新函数
因为函数参数调整,同步修改updateItemToCart适配新的传参:
updateItemToCart = (product, attrType, newAttrValue) => { this.setState({ cartItems: this.updateCartItem(this.state.cartItems, product, attrType, newAttrValue), }); };
调用方式
触发属性修改时(比如点击颜色选项),直接传入对应参数即可:
// 示例:将id为product1的商品Color属性修改为#FFFFFF this.updateItemToCart(product, "Color", "#FFFFFF");
内容的提问来源于stack exchange,提问作者aarriiaann
相关产品推荐
相关产品推荐

