簡體   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