useState hook, setState function. Accessing previous state value
Asked Answered
C

1

24

Are these two equivalent? If not which is best and why?

const [count, setCount] = useState(initialCount);
<button onClick={() => setCount(count + 1)}>+</button>
const [count, setCount] = useState(initialCount);
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
Castellano answered 1/6, 2019 at 7:45 Comment(0)
G
30

If the next state value depends on the previous value, as in this example of an increment button, it's better to use the functional version of setState (setCount(prevCount => prevCount + 1)).

You can run into errors if you're passing the setter function into a callback function, like an onChange or HTTP Request response handler.

As an explicit example, in the below page, if you click "Delayed Counter (basic)" and then click "Immediate Counter", the count will only increment by 1. However, if you click "Delayed Counter (functional)", followed by "Immediate Counter", the count will eventually increment by 2.

import React, { useState } from "react";
import ReactDOM from "react-dom";

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => setTimeout(() => setCount(count + 1), 2000)}>
        Delayed Counter (basic)
      </button>
      <button onClick={() => setTimeout(() => setCount(x => x + 1), 2000)}>
        Delayed Counter (functional)
      </button>
      <button onClick={() => setCount(count + 1)}>Immediate Counter</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement);
Ghazi answered 30/1, 2020 at 16:54 Comment(1)
The reason why this happens as far as I understand, is that the "basic" counter saves the value of "count" in memory when it gets called and uses that same value regardless of whether it has changed in the meantime or not. Maybe this is helpful to someone ;)Propaganda

© 2022 - 2024 — McMap. All rights reserved.