I have an a state object in React that looks something like this (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: [] } ] }
I have code that adds or inserts a new chapter object that is working. I am using:
// for creating a new chapter: setSelectedBook(old => { return { ...old, chapters: [ ...old.chapters, newChapter // insert new object ] } })
And for the chapter update, this is working:
setSelectedBook(old => { return { ...old, chapters: [ ...old.chapters.map(ch => { return ch.id === selectedChapterId ? {...ch, name: selectedChapter.name} : ch }) ] } })
But for my update/create for the sections, I’m having trouble using the same approach. I’m getting syntax errors trying to access the sections from book.chapters. For example, with the add I need:
// 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? ] } })
I know with React you’re supposed to return all the previous state except for what you’re changing. Would a reducer make a difference or not really?
I should note, I have 4 simple lists in my ui. A list of books/chapters/sections/items, and on any given operation I’m only adding/updating a particular level/object at a time and sending that object to the backend api on each save. So it’s books for list 1 and selectedBook.chapters for list 2, and selectedChapter.sections for list 3 and selectedSection.items for list 4.
But I need to display the new state when done saving. I thought I could do that with one bookState object and a selectedThing state for whatever you’re working on.
Hopefully that makes sense. I haven’t had to do this before. Thanks for any guidance.
Advertisement
Answer
for adding new Section
setSelectedBook( book =>{ let selectedChapter = book.chapters.find(ch => ch.id === selectedChapterId ) selectedChapter.sections=[...selectedChapter.sections, newSection ] return {...book} })
For updating a section’s name
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} })
For updating item’s name
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} })
I hope you can see the pattern.