代码之家  ›  专栏  ›  技术社区  ›  Dglfwcfa

将两个状态组合成一个,并将内容排序到嵌套对象中

  •  1
  • Dglfwcfa  · 技术社区  · 4 月前

    我有两个州,一个有类别,另一个有项目。

    我只需要一个最终状态,通过合并一个状态来组合这两个状态 进入另一种状态或通过形成第三种状态。

    类别状态如下:

    {
    category1: { items: [] },
    category2: { items: [] }
    }
    

    第二个状态是一个项目数组,它看起来像这样:

    [
    {"id": "1", itemInfo: { name: "itemName", category: "category1" }},
    {"id": "2", itemInfo: { name: "itemName", category: "category1" }},
    {"id": "3", itemInfo: { name: "itemName", category: "category2" }},
    {"id": "4", itemInfo: { name: "itemName", category: "category1" }},
    {"id": "5", itemInfo: { name: "itemName", category: "category2" }},
    {"id": "6", itemInfo: { name: "itemName", category: "category2" }}
    ]
    

    我需要它是这样的:

    {
    category1: { items: [
        {"id": "1", itemInfo: { name: "itemName", category: "category1" }},
        {"id": "2", itemInfo: { name: "itemName", category: "category1" }},
        {"id": "4", itemInfo: { name: "itemName", category: "category1" }}
    ]},
    
    category2: { items: [
        {"id": "3", itemInfo: { name: "itemName", category: "category2" }},
        {"id": "5", itemInfo: { name: "itemName", category: "category2" }},
        {"id": "6", itemInfo: { name: "itemName", category: "category2" }}
    ]}
    }
    

    帮助。拜托。

    这是我尝试过但没有成功的方法,它要么重复了类别,最终得到3个“类别1”和3个“分类2”,要么新项目覆盖了以前的项目。

    const newFinalList = items.map((item: any) => {
        return {[item.itemInfo.category]: {items: [item]}}
    }) 
    
    setFinalState((prevObj: any) => ({ ...prevObj, ...newFinalList }))
    
    2 回复  |  直到 4 月前
        1
  •  3
  •   Drew Reese    4 月前

    问题

    问题是数组映射返回一个新数组,但您希望将数组映射到 categories 状态形状是一个对象。映射逻辑为源数组中的每个item元素返回一个对象。

    const newFinalList = items.map((item: any) => {
      return {                                      // <-- new object for each item
        [item.itemInfo.category]: { items: [item] } // <-- only one item in each items array
      }
    })
    

    解决方案

    减少 将数组转换为对象。

    例子:

    // Iterate the items array and reduce into an object
    const newFinalList = items.reduce((categories, item) => {
      // If the item category object doesn't exist, create it
      // with an initially empty items array
      if (!categories[item.itemInfo.category]) {
        categories[item.itemInfo.category] = {
          items: [],
        };
      }
    
      // Push the current item into the items array
      categories[item.itemInfo.category].items.push(item);
    
      // return the categories object
      return categories;
    }, {});
    

    const items = [
      { id: "1", itemInfo: { name: "itemName", category: "category1" } },
      { id: "2", itemInfo: { name: "itemName", category: "category1" } },
      { id: "3", itemInfo: { name: "itemName", category: "category2" } },
      { id: "4", itemInfo: { name: "itemName", category: "category1" } },
      { id: "5", itemInfo: { name: "itemName", category: "category2" } },
      { id: "6", itemInfo: { name: "itemName", category: "category2" } },
    ];
    
    const newFinalList = items.reduce((categories, item) => {
      if (!categories[item.itemInfo.category]) {
        categories[item.itemInfo.category] = {
          items: [],
        };
      }
      categories[item.itemInfo.category].items.push(item);
      return categories;
    }, {});
    
    console.log({ newFinalList });

    如果你用它来合并一些传递的props/context值,它是一个React反模式,也可以将这个派生的“状态”存储到React状态中。要么直接计算并使用该值,要么使用 React.useMemo 钩子计算并提供稳定的参考值。

    const newFinalList = React.useMemo(() => items.reduce((categories, item) => {
      if (!categories[item.itemInfo.category]) {
        categories[item.itemInfo.category] = {
          items: [],
        };
      }
    
      categories[item.itemInfo.category].items.push(item);
      return categories;
    }, {}), [items]);
    
        2
  •  1
  •   Nick Parsons Felix Kling    4 月前

    Drew很好地指出了为什么你现有的尝试不起作用。如果你想合并你的第一个状态(类别),这样它就包括了你的项目状态中具有相应类别的项目,那么你可以首先让你的项目的状态成为一个查找图,将项目类别映射到项目对象,然后通过你的 categories 通过记录并调用来进行状态 .map() 将项目添加到每个对象中。然后,您可以致电 Object.fromEntries() 将其转换回对象:

    const categories = { category1: { items: [] }, category2: { items: [] } };
    const items = [ {"id": "1", itemInfo: { name: "itemName", category: "category1" }}, {"id": "2", itemInfo: { name: "itemName", category: "category1" }}, {"id": "3", itemInfo: { name: "itemName", category: "category2" }}, {"id": "4", itemInfo: { name: "itemName", category: "category1" }}, {"id": "5", itemInfo: { name: "itemName", category: "category2" }}, {"id": "6", itemInfo: { name: "itemName", category: "category2" }} ];
    
    const itemsMap = Map.groupBy(items, o => o.itemInfo.category);
    const merged = Object.fromEntries(Object.entries(categories).map(([key, val]) => [
      key,
      {...val, items: val.items.concat(itemsMap.get(key))}
    ]));
    console.log(merged);