[英]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。
优点:
createNextState
的形式公开(请仔细查看文档)。normalizr
(长话)的一个有趣用例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.