12

How do I call setState with the previous state plus an additional value in a controlled component?

The typical example is:

Increment() {
    this.setState((prevState, props) => ({counter: prevState.counter = props.step})
}

However, how do you update the state based on the prevState and a value from a handler. For example (and I know this example is wrong, since you cannot pass value into the setState callback):

HandleOnAddItem(evt, { value }) {
    this.setState((prevState, props, value) -> ({items: value, ...prevState.items})
}
mdebeus
  • 1,928
  • 3
  • 18
  • 27

2 Answers2

15

If you are passing that value in event handler function, then it will be available inside setState without passing into updater function.

Write it like this:

HandleOnAddItem(evt, { value }) {
    this.setState((prevState, props) => ({items: value, ...prevState.items}))
}

If you are updating only one state property that doesn't dependent on previous state, as i think in your case, then directly you can write:

HandleOnAddItem(evt, { value }) {
    this.setState({ items: value })
}

Check this answer for more details: How do JavaScript closures work?

Example:

//setTimeout will call the method after 2sec, similar to setState
let abc = a => {setTimeout(() => console.log('a', a), 2000)}; 

abc(10);
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • Why is the spread syntax applied after a new value has been updated, does it matter? Or is it a semantic issue? – Munib Jan 10 '22 at 23:39
1

Because of javascript closures, inner functions have access to the variables of outer functions, a value passed as parameter on to the handler function is available in the setState callback. You can use it like

HandleOnAddItem(evt, { value }) {
    this.setState((prevState, props) -> ({items: value, ...prevState.items})
}
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400