繁体   English   中英

如何使用 useState 添加、更新或删除嵌套对象

[英]How to add, update or remove nested objects with useState

我有一个可能的无限类别树,我想使用 setState 在任何级别添加、更新或删除类别。 我知道这可以通过递归实现,但我没有足够的经验来自己解决这个问题。 以下是数据可能的样子:

const categories = [
  {
    id: "1",
    name: "category1",
    subCategories: [
      {
        id: "sub1",
        name: "subcategory1",
        subCategories: [
          { id: "subsub1", name: "subsubcategory1", subCategories: [] },
          { id: "subsub2", name: "subsubcategory2", subCategories: [] }
        ]
      },
      { id: "sub2", name: "subcategory2", subCategories: [] }
    ]
  },
  {
    id: "2",
    name: "category2",
    subCategories: []
  }
]

考虑到您的顶级类别对象是对象而不是数组,添加和删除函数可能如下(更新模式相同)

function add (tree, newCategory, parentId) {
    if(tree.id === parentId) 
      return {
        ...tree,
        subCategories: tree.subCategories.concat(newCategory)
      }
    return {
        ...tree, 
        subCategories: tree.subCategories.map(c => add(c, newCategory, parentId))
    }
}



function remove (tree, idToRemove) {
        if(tree.subCategories.map(c => c.id).includes(idToRemove)) 
          return {
            ...tree,
            subCategories: tree.subCategories.filter(c => c.id !== idToRemove)
          }
        return {
            ...tree, 
            subCategories: tree.subCategories.map(c => remove(c, idToRemove))
        }
    }

这就是递归函数的样子。 论据:

id:要查找的id

猫:要循环的类别数组

nestSubCategory: (boolean) 是否要在 subCategories 数组中添加子类别对象

subCategory:我们要插入的类别对象

const addCategories = (id, cats, nestSubCategory, subCategory)=> {
  const cat = cats.find(item=> item.id === id)
  
  const arrSubs = cats.filter(item => item.subCategories?.length)
  .map(item => item.subCategories)
 
  if(cat){
    if(nestSubCategory){
       cat.subCategories.push(subCategory)
       return
    }else{
       cats.push(subCategory)
       return
    }
  }
  
  else{
    return addCategories(id, arrSubs[0], nestSubCategory, subCategory)
  }
    
}
  

addCategories("blabla1", categories, true,  { id: "blabla2", name: "blablacategory1", subCategories: [] })
  //console.log(categories)
console.log(
  JSON.stringify(categories)
  )

记住在函数执行后更新处于替换整个类别数组的状态的对象。 小心递归🖖🏽

您可以以类似的方式删除项目,我留给您尝试的乐趣

序幕

要以不可变的方式更新嵌套属性,您需要在其所有父级上复制或执行不可变操作。

在嵌套对象上设置属性:

return {
  ...parent,
  person: {
    ...parent.person,
    name: 'New Name'
  }
}

数组:您可以预先克隆数组,或使用.slice().map().filter()和连接运算符 ( ... ) 的组合; 警告: .splice 会改变数组。

(这可能是一个很长的话题,所以我只是给出了一个非常快速的概述)

沉浸

由于这在具有深度嵌套的对象上很快就会变得非常难看,因此在某些时候使用immer库非常必要。 Immer “从突变中创建新的不可变状态”。

const newState = immer(oldState, draft => {
  draft[1].subcategories[3].subcategories[1].name = 'Category'
})

在极端情况下,您可以将 immer 与 lodash 结合起来在任意位置创建突变:

import set from 'lodash/set'
const newState = immer(oldState, draft => {
  set(draft, [0, 'subcategories', 5, 'subcategories', 3], { id: 5, name:'Cat' })
})

“你可能不需要 lodash”网站有 lodash/set 的递归实现。 但是,说真的,只需使用 lodash。

优点:

  • 如果您使用的是 redux-toolkit,则 immer 已经自动应用于 reducer,并以createNextState的形式公开(请仔细查看文档)。
  • 深度嵌套状态可能是normalizr (长话)的一个有趣用例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM