Are "How to delete an item from state array?" answers wrong cuz setState is async?

Viewed 44

In this SO question, all the answers use this form of setState:

this.setState( { items: this.state.items.filter() } )

Which means this is a case of "new state is derived from the current state".

However, in this React Doc about async behavior of setState, in this case, this callback form MUST be used instead:

this.setState( currState => ( { items: currState.items.filter() } ) )

My question is, are those answer all wrong, and if so, what are the consequences? Or is it somehow still acceptable?

1 Answers

The issue only occurs if your code design is (what I think) "bad". Normally, you expect to update the value that is used in the current render. So for example, if the currently displayed num is 5, and you want to increase it, you would want the number to be 6. But if you now set the num to 10 before doing setNum(num + 1), the output won't be 11, but 6, because it used the currently rendered value (5) + 1 (Which is what I would expect). If you wanted it to use "the current state", so the 10 from the previous setNum, you would need to use the callback version.

That was sort of complicated, so here an example:

import React, { useState } from 'react';

export default ({ name }) => {
  const [num, setNum] = useState(5);

  return (
    <React.Fragment>
      <h1>{num}</h1>
      <button onClick={changed}>Change!</button>
      <button onClick={changedWithCallback}>Change with callback!</button>
      <button onClick={resetted}>Reset!</button>
    </React.Fragment>
  );

  function changed() {
    setNum(10);
    setNum(num + 1);
  }

  function changedWithCallback() {
    setNum(10);
    setNum((state) => state + 1);
  }

  function resetted() {
    setNum(5);
  }
};

Working example

Related