如何从单个JavaScript对象中提取同类数据生成数组
问题:从对象提取同类商品数组时仅保留最后一个元素
问题场景
需要从以下大型对象(moreProductInfo1)中提取同类商品数据,整理为包含商品对象的数组:
{ "SKU1": "1", "productId1": "2", "condition1": "Refurbrished", "price1": "3", "quantity1": "4", "colorMap1": "5", "SKU2": "11", "SKU3": "111", "productId2": "22", "productId3": "222", "condition2": "Old", "condition3": "Used", "price2": "33", "price3": "333", "quantity2": "44", "quantity3": "444", "colorMap2": "55", "colorMap3": "555" }
期望得到的结果:
[{ "SKU": "1", "productId": "2", "condition": "Refurbrished", "price": "3", "quantity": "4", "colorMap": "5", "attribute": "Color", "attributeValue": "violet" }, { "SKU": "11", "productId": "22", "condition": "Old", "price": "33", "quantity": "44", "colorMap": "55", "attribute": "Quality", "attributeValue": "New" }, { "SKU": "111", "productId": "222", "condition": "Used", "price": "333", "quantity": "444", "colorMap": "555", "attribute": "Material", "attributeValue": "Cotton" }]
使用addedVariation数组确定商品数量(本次为3个):
[ { "Color": "violet" }, { "Quality": "New" }, { "Material": "Cotton" } ]
尝试的代码如下,但最终结果仅保留最后一个商品对象:
... const [productsArray, setProductsArray] = useState([]); ... addedVariation.map((curr, idx, arr) => { for (var key of Object?.keys(moreProductInfo1)) { if (key?.includes(`${idx + 1}`)) { setProductsArray([ ...productsArray, { attribute: Object?.keys(curr)?.[idx], attributeValue: Object?.values(curr)?.[idx], SKU: moreProductInfo1?.[`SKU${idx + 1}`], productId: moreProductInfo1?.[`productId${idx + 1}`], condition: moreProductInfo1?.[`condition${idx + 1}`], price: moreProductInfo1?.[`price${idx + 1}`], quantity: moreProductInfo1?.[`quantity${idx + 1}`], colorMap: moreProductInfo1?.[`colorMap${idx + 1}`], }, ]); } } }); ...
问题分析
- useState异步更新导致状态覆盖:
setProductsArray是异步操作,循环中每次调用时,productsArray始终是初始的空数组,所以每次更新都是[newItem],最终只保留最后一次的结果。 - 冗余的键遍历:嵌套
for...of遍历moreProductInfo1的键完全没必要,通过idx+1拼接键名就能直接获取对应值。 - attribute获取错误:
Object.keys(curr)?.[idx]中,curr是单个键值对的对象,idx会超出索引范围(比如第二个对象idx=1,但Object.keys(curr)只有一个元素),导致attribute值为undefined。
解决方案
方案一:先构建完整数组再更新状态(推荐)
先一次性生成所有商品对象的数组,再调用setProductsArray更新状态,避免异步更新的问题:
const [productsArray, setProductsArray] = useState([]); // 构建商品数组 const newProducts = addedVariation.map((curr, idx) => { const suffix = idx + 1; // 提取当前variation的键值对 const [attribute, attributeValue] = Object.entries(curr)[0]; return { attribute, attributeValue, SKU: moreProductInfo1[`SKU${suffix}`], productId: moreProductInfo1[`productId${suffix}`], condition: moreProductInfo1[`condition${suffix}`], price: moreProductInfo1[`price${suffix}`], quantity: moreProductInfo1[`quantity${suffix}`], colorMap: moreProductInfo1[`colorMap${suffix}`] }; }); // 一次性更新状态 setProductsArray(newProducts);
方案二:使用函数式更新(适合需要逐步更新的场景)
如果必须在循环中更新状态,使用setState的函数式形式,确保每次更新都基于最新的状态:
const [productsArray, setProductsArray] = useState([]); // 先清空旧数组(按需选择) setProductsArray([]); addedVariation.forEach((curr, idx) => { const suffix = idx + 1; const [attribute, attributeValue] = Object.entries(curr)[0]; // 函数式更新,基于最新状态添加新元素 setProductsArray(prevProducts => [ ...prevProducts, { attribute, attributeValue, SKU: moreProductInfo1[`SKU${suffix}`], productId: moreProductInfo1[`productId${suffix}`], condition: moreProductInfo1[`condition${suffix}`], price: moreProductInfo1[`price${suffix}`], quantity: moreProductInfo1[`quantity${suffix}`], colorMap: moreProductInfo1[`colorMap${suffix}`] } ]); });
说明
- 方案一效率更高,减少状态更新次数,适合一次性生成所有数据的场景。
- 方案二通过函数式更新
prevProducts => [...prevProducts, newItem],确保每次更新都使用最新的数组状态,不会覆盖之前的元素。 - 用
Object.entries(curr)[0]正确提取单个对象的键值对,避免索引错误。
内容的提问来源于stack exchange,提问作者Youzef
相关产品推荐
相关产品推荐

