Я довольно новичок в реакции / ES6, и у меня странное поведение, когда я использую метод Reduce для преобразования плоского массива, полученного из API, во вложенный объект.Я уже был хорошо знаком с картой и фильтром, но никогда раньше не использовал Reduce.
Я почти уверен, что я использую его неправильно, но так оно и есть.
У меня есть следующий набор плоских данных:
[
{
category:"Category1",
subCategory:"SubCategory1",
productType:"ProductType1",
brand:"brand1"
},
{
category:"Category1",
subCategory:"SubCategory2",
productType:"ProductType2",
brand:"brand2"
},
{
category:"Category1",
subCategory:"SubCategory2",
productType:"ProductType2",
brand:"brand3"
},
{
category:"Category2",
subCategory:"SubCategory1",
productType:"ProductType1",
brand:"brand1"
},
{
category:"Category2",
subCategory:"SubCategory1",
productType:"ProductType2",
brand:"brand2"
}
]
Я использую следующий код для получения вложенного объекта из плоского набора данных.
getNestedData() {
var baseData = this.getBaseData();
return baseData.reduce((categories,category) => {
if(!categories[category.category]){
categories[category.category] = {
category: category.category,
subCategories: baseData.filter(bd => bd.category === category.category)
.reduce((subCategories,subCategory) => {
if(!subCategories[subCategory.subCategory]) {
subCategories[subCategory.subCategory] = {
subCategory: subCategory.subCategory,
productTypes: baseData.filter(bd => bd.category === subCategory.category && bd.subCategory === subCategory.subCategory)
.reduce((productTypes,productType) => {
if(!productTypes[productType.productType]) {
productTypes[productType.productType] = {
productType: productType.productType,
brands: baseData.filter(bd => bd.category === productType.category && bd.subCategory === productType.subCategory && bd.productType === productType.productType)
.reduce((brands,brand) => {
if(!brands[brand.brand]) {
brands[brand.brand] = {
brand: brand.brand
}
}
return brands;
})
};
}
return productTypes;
})
};
}
return subCategories;
})
}
}
return categories;
});
}
Однакорезультат не то, что я ожидал.Возвращает объект корневого массива внутри первой категории массива.Как Category1 => [Category1,Category2]
.И если вы перейдете под ребенка категории 1, произойдет то же самое.
Я подготовил следующее jsFiddle , чтобы показать мою проблему.
Дайте мне знать, что я делаю неправильно, ягуглил это часами.Я также хотел бы знать, является ли этот способ наиболее эффективным?
Редактировать:
Есть пример ожидаемого результата:
[
{
category: "Category1"
subCategories:[
{
subCategory:"SubCategory1",
productTypes:[
{
productType:"ProductType1",
brands:["Brand1"]
}
]
},
{
subCategory:"SubCategory2",
productTypes:[
{
productType:"ProductType2",
brands:["Brand2","Brand3"]
}
]
}
]
},
{
category: "Category2",
subCategories:[
{
subCategory:"SubCategory1",
productTypes:[
{
productType:"ProductType1",
brands:["Brand1"]
},
{
productType:"ProductType2",
brands:["Brand2"]
}
]
}
]
}
]
Редактировать
Мэт был прав, я забыл передать начальное значение, когда использовал уменьшение.Передача начального значения сделала сокращение работы, как я и ожидал.Затем я смог изменить свой код, чтобы получить ожидаемый результат.Код не самый элегантный, но работает очень хорошо:
getNestedData()
{
var baseData = this.getBaseData();
return baseData
.map(c => {return c.category;})
.reduce((categories,category) => {
var currentCategory = categories.filter(
c => c.category === category
);
if (currentCategory.length === 0) {
var categoryData = baseData.filter(bd => bd.category === category);
categories.push({
category:category,
subCategories: categoryData
.map(c => {return c.subCategory})
.reduce((subCategories,subCategory) => {
var currentSubCategory = subCategories.filter(sc => sc.subCategory === subCategory)
if(currentSubCategory.length === 0)
{
var subCategoryData = categoryData.filter(cd => cd.subCategory === subCategory);
subCategories.push({
subCategory:subCategory,
productTypes: subCategoryData
.map(scd => {return scd.productType})
.reduce((productTypes,productType) => {
var currentproductType = productTypes.filter(pt => pt.productType === productType);
if(currentproductType.length === 0)
{
var productTypeData = subCategoryData.filter(scd => scd.productType === productType)
productTypes.push({
productType:productType,
brands: productTypeData
.map(ptd => {return ptd.brand})
.reduce((brands,brand) => {
var currentBrand = brands.filter(b => b.brand === brand);
if(currentBrand.length === 0)
{
brands.push({brand:brand});
}
return brands;
},[])
});
}
return productTypes;
},[])
});
}
return subCategories;
},[])
});
}
return categories;
},[])
}
Там - это рабочий jsFiddle с ожидаемым поведением.