Javascript: Spread array of an object in an object and change properties inside it only

I have a scenario where I want to change properties of object in an array. That array is wrapped inside another object.


const defaultData = {
  title: "Title",
  subtitle: "Subtitle",
  books: [
    {
      bookId: "1",
      imageSrc:
        "any.png",
      name: "Issue",
      userOwnsData: true,
      panelsCollected: 0,
      totalPanels: 123,
      link: "https://google.com",
    },
  ],
  bgColor: "black",
};

When I spread it like this:

{...defaultData, ...defaultData.books[0], panelsCollected:123} //previously it was 0

then it adds another extra object to parent object but not update it inside first index of books array

How can I just change that panelsCollected property without disturbing whole structure as we are using typescript.

Thanks

>Solution :

When spreading an object with nested properties with the intention of updating specific properties, think of it in two steps:

  1. Spread the original object to copy it (...)
  2. Redefine the new property values after the spread object

In your example we are doing the following:

  • Duplicating defaultData and assigning an updated books property (to be defined in the next step)
  • Duplicating the first book (defaultData.books[0]) and assigning an updated panelsCollected property to it. Then overwriting the existing books property with this updated array item

The result is as follows:

const defaultData = {
  title: "Title",
  subtitle: "Subtitle",
  books: [
    {
      bookId: "1",
      imageSrc:
        "any.png",
      name: "Issue",
      userOwnsData: true,
      panelsCollected: 0,
      totalPanels: 123,
      link: "https://google.com",
    },
  ],
  bgColor: "black",
};

const newBook = {
  ...defaultData,
  books: [
    {
      ...defaultData.books[0],
      panelsCollected: 123
    }
  ]
}

console.log(newBook)
/*
{
  title: "Title",
  subtitle: "Subtitle",
  books: [
    {
      bookId: "1",
      imageSrc:
        "any.png",
      name: "Issue",
      userOwnsData: true,
      panelsCollected: 123,
      totalPanels: 123,
      link: "https://google.com",
    },
  ],
  bgColor: "black",
};
*/

If for example the books property was 1000 items long, you would instead use have to find the specific book in your array using an array method (e.g. find / findIndex) and update it, e.g.

const bookToUpdateIndex = defaultData.books.findIndex(book => bookId === '1')

const updatedBooks = defaultData.books
updatedBooks[bookToUpdateIndex] = {
  ...updatedBooks[bookToUpdateIndex],
  panelsCollected: 123
}

const newBook = {
  ...defaultData,
  books: updatedBooks
}

Leave a Reply