[英]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.