-1

This is really trivial, but I'm looking for a preferred way and can't seem to find it.

I have a object, like this:

const input = {
  aaa: "bee",
  foo: "bar",
  fizz: "buz",
  (...)
}

How do I change it to:

const input = {
  aaa: "bee",
  foo: "CHANGED",
  fizz: "buz",
  (...)
}

Without using assignment e.g input.foo = "CHANGED"?

I'm setting a state in React so I wanted to do something like setState(...input, foo: "CHANGED") but I can't use ... as it's not an array. What am I missing? Is there even an elegant way for what I'm looking for? Do I have to map? Or is there a one liner?

Wordpressor
  • 7,173
  • 23
  • 69
  • 108
  • Prefer doing things in a way that is easy to read and maintain over "elegant" or "in one line". I can't tell you how many hours of time have been wasted tracking down bugs only to find out it's because someone decided to be clever. – Heretic Monkey May 21 '21 at 00:29
  • Also, duplicate of [What is the shortest way to modify immutable objects using spread and destructuring operators](https://stackoverflow.com/q/36553129/215552) – Heretic Monkey May 21 '21 at 00:30

3 Answers3

1

You can use ... in objects too:

  const [foo, setFoo] = useState({
    bar: "example",
    baz: "this will change"
  });


  setFoo({
    ...foo,
    baz: "changed"
  });
Saissaken
  • 87
  • 4
  • TS throws an error here: `Type 'InputData' is not an array type`. BTW I'm using useState with hooks. – Wordpressor May 20 '21 at 23:43
  • I've updated the answer with a useState hook example. I had no issue running it on my side, neither a TS error. Double check that you are referring to the correct variables. – Saissaken May 20 '21 at 23:57
0

What you're looking for is destructuring assignment

This works for objects as well

    const [testing, setTesting] = useState({a: 1, b: 2});

    setTesting({
        ...testing,
        a: 5
    });

Robert Tirta
  • 2,593
  • 3
  • 18
  • 37
0

Spread operator is ok but beware that this will only do a shallow clone.

When setting state in React, if you haven't correctly cloned the object, you will create a world of headaches.

Personally, if it isn't going to make the code too inefficient, I would use lodash deep clone on objects before changing the cloned object, then I would assign it to the state.

import _ from 'lodash'

// Then inside your class component

const nextState = _.cloneDeep(this.state.myObject)

nextState.someKey = "someValue"

this.setState({myObject: nextState})

Alternatively, you could just create your own deep clone function like this:

const cloneDeep = (obj) => JSON.parse(JSON.stringify(obj))

Though apparently, this isn't very efficient. I'm sure you won't notice much difference with a small state though.

In my opinion (I'm sure many will disagree), having been through the confusion of incorrectly assigning state when I was learning, I think you are best to just use a deep clone function on everything before assigning it to state. Then once you become more familiar with React, come back and wrap your head around the nuances of the spread operator and assigning state correctly.

Steve
  • 4,372
  • 26
  • 37