Naigel
Naigel

Reputation: 9644

Spread syntax for complex objects

Assume I have an object like this

let store = {
  "articles": [{...}, {...}, ...],
  "errors": { "p1": { "myNewObject":0 }, "p2": {...}, ...}
}

I want to take advantage of Spread syntax to return a clone of this object where store.errors.p1 is a new object. Is the following the simplest way?

let newStore = { ...store, ...{ errors: { ...store.errors, p1: { "myNewObject":1 } } } }

Upvotes: 3

Views: 526

Answers (3)

jo_va
jo_va

Reputation: 13964

No it is not the simplest syntax to clone your store and do a deep copy of p1, but it's very close:

let newStore = { ...store, ...{ errors: { ...store.errors, p1: { myNewObject: 1 } } } }
//                         ^^^^                                                     ^
//                           |_______ not necessary ________________________________|

You can remove the extra spread and brackets around errors.

const store = { articles: [{ a: 1 }], errors: { p1: { myNewObject: 0 }, p2: { a: 1 } } }

const newStore = { ...store, errors: { ...store.errors, p1: { myNewObject: 1 } } }

console.log(JSON.stringify(store))
console.log(JSON.stringify(newStore))

Upvotes: 4

Sushanth --
Sushanth --

Reputation: 55740

If you feel this is not readable then you could use a reduce to iterate over errors object and update the object first and then use spread syntax. It might be a bit more lines of code but will offset for readability.

const updatedkey = "p1";
const updatedData = {
  "myNewObject": 1
};
const store = {
  "articles": [{
    ...
  }, {
    ...
  }],
  "errors": {
    "p1": {
      "myNewObject": 0
    },
    "p2": {
      ...
    },
  }
};
const updatedErrors = Object.keys(store.errors).reduce((acc, key) => {
  const acc[key] = store.errors[key];

  if (key === updatedkey) {
    acc[key] = {
      ...acc[key],
      ...updatedData
    }
  }

  return acc;
}, {});

const newStore = {
  ...store,
  errors: updatedErrors
};

Upvotes: 0

You could also use something as lodash.clonedeep an then just change that property with store.errors.p1 = { "myNewObject": 1}.

Or if you want, you could create a function assocIn (inspired by clojue) that does it in a more idiomatic way:

const assocIn = (obj, [key, ...rest], value) => 
    ({...obj, [key]: rest.length == 0 ? value : assocIn(obj[key], rest, value)});
store = assocIn(store, ['errors', 'p1'], { "myNewObject": 1})

Upvotes: 0

Related Questions