使用react钩子(add或update)维护一个分层对象的react状态



我在React中有一个状态对象,看起来像这样(book/chapter/section/item):

const book = {
id: "123",
name: "book1",
chapters: [
{
id: "123",
name: "chapter1", 
sections: [
{
id: "4r4",
name: "section1",
items: [
{
id: "443",
name: "some item"
}
]
}
]
}, 
{
id: "222",
name: "chapter2",
sections: []
}
]
}

我有添加或插入正在工作的新章对象的代码。我正在使用:

// for creating a new chapter:
setSelectedBook(old => {
return {
...old,
chapters: [
...old.chapters, 
newChapter // insert new object
]
}
})

对于章节更新,这是有效的:

setSelectedBook(old => {
return {
...old,
chapters: [
...old.chapters.map(ch => {
return ch.id === selectedChapterId
? {...ch, name: selectedChapter.name}
: ch
})
]
}
})

但是对于我的更新/创建的部分,我有麻烦使用相同的方法。我得到语法错误试图访问部分从书。章节。例如,使用我需要的add:

// for creating a new section:
setSelectedBook(old => {
return {
...old,
chapters: [
...old.chapters,
...old.chapters.sections? 
newSection // how to copy chapters and the sections and insert a new one?
]
}
})

我知道React应该返回所有以前的状态,除了你正在改变的。减速器真的会产生影响吗?

我应该注意,我有4个简单的列表在我的ui。一个书籍/章节/章节/项目的列表,在任何给定的操作中,我一次只添加/更新一个特定的关卡/对象,并在每次保存时将该对象发送给后端api。这里是books for list 1和selectedBook。并选择了ecectedchapter。和selectedSection。清单4.

但是我需要在保存完成时显示新的状态。我想我可以用一个bookState对象和一个selectedThing状态来实现这一点。

希望这是有意义的。我以前从没这么做过。谢谢你的指导。

用于添加新的Section

setSelectedBook( book =>{
let selectedChapter = book.chapters.find(ch => ch.id === selectedChapterId )
selectedChapter.sections=[...selectedChapter.sections, newSection ]
return {...book}
})

用于更新section名

setSelectedBook(book=>{
let selectedChapter = book.chapters.find(ch => ch.id === selectedChapterId )
let selectedSection = selectedChapter.sections.find(sec => sec.id === selectedSectionId )
selectedSection.name = newName
return {...book}
})

用于更新项目名称

setSelectedBook(book =>{
let selectedChapter = book.chapters.find(ch => ch.id === selectedChapterId )
let selectedSection = selectedChapter.sections.find(sec => sec.id === selectedSectionId )
let selectedItem = selectedSection.items.find(itm => itm.id === selectedItemId) 
selectedItem.name = newItemName
return {...book}
})

我希望你能看到这个模式。

我认为这个地图应该适用于这个用例,就像你的例子一样。

setSelectedBook(old => {
return {
...old,
chapters: [
...old.chapters.map(ch => {
return { ...ch, sections: [...ch.sections, newSection] }
})
]
}
})

在你的最后一个代码块中,你试图将章节,章节和新章节放在同一级别的同一数组中,而不是彼此内部。

在React中更新深层嵌套状态对象总是很困难。在不了解实现的所有细节的情况下,很难说如何进行优化,但您应该认真考虑以更平坦的方式存储该状态的不同方法。有时这是不可能的,在这种情况下,有像Immer这样的库可以帮助您查看。

使用您在问题中提供的状态对象,也许您可以将所有这些数组变为具有id为key的对象:

const book = {
id: "123",
name: "book1",
chapters: {
"123": {
id: "123",
name: "chapter1", 
sections: {
"4r4": {
id: "4r4",
name: "section1",
items: {
"443": {
id: "443",
name: "some item"
}
}
}
}
}, 
"222": {
id: "222",
name: "chapter2",
sections: {},
}
]
}

这样,在设置状态时就不再需要使用mapfind了。

// for creating a new chapter:
setSelectedBook(old => {
return {
...old,
chapters: {
...old.chapters, 
[newChapter.id]: newChapter
}
}
})
// for updating a chapter:
setSelectedBook(old => {
return {
...old,
chapters: {
...old.chapters, 
[selectedChapter.id]: selectedChapter,
}
}
})
// for updating a section:
setSelectedBook(old => {
return {
...old,
chapters: {
...old.chapters, 
[selectedChapter.id]: {
...selectedChapter,
sections: {
[selectedSectionId]: selectedSection
}
},
}
}
})

请让我知道如果我误解了你的问题。

最新更新