How to update a value instantaneously instead of asynchronously in React
Tags: react, beginners
Published: 2023-11-15 19:49:54

# Overview
* `useState` doesn't update a value instantaneously, so that value will be as it was even if it's accessed soon after `useState` like below.

cf. https://ja.react.dev/reference/react/useState#usage

* React handles the accumulated queues and updates state in bulk after all events executing in parallel completed being done.
* After that, components are re-rendered.

cf. https://ja.react.dev/learn/queueing-a-series-of-state-updates

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

  function handleClick() {
    setCount(count + 1);
    console.log(count); // 0
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}
```

# useRef
* Use `useRef` as "escape hatch" to get the latest updated state when `setState` is called in an asynchronous event(function).

##### Gist
* `setState` is an asynchronous function.
* The queue for updating the state is not captured by the lifecycle of the state in React when it is called in an asynchronous function. So the state is not updated then.

cf. https://crybabe.net/archives/12#toc1

cf. https://ja.react.dev/learn/referencing-values-with-refs#when-to-use-refs

```React
function Example() {
  const [count, setCount] = useState(0);
  const [count2, setCount2] = useState(0);
  const countRef = useRef(0);

  const handleClick = () => {
    setTimeout(() => {
      setCount(count + 1);
      console.log(count); // 0
      setCount2(count => count + 1);
      console.log(count); // 1
      countRef.current += 1;
      console.log(countRef.current); // 1
    }, 1000);
  };

  const onSubmit = () => {
    console.log(count); // 0
    console.log(count2); // 0
    console.log(countRef.current); // 1
  };

  return (
    <div>
      <p>{countRef.current}</p>
      <button onClick={handleClick}>Click me</button>
      <button onClick={onSubmit}>Submit</button>
    </div>
  );
}

export default Example;
```

However, you need to be careful about the point `useRef` is independent of the React rendering cycle and so doesn't update DOM.

In principle, it's important to design the overall logic in the component so that they can work even if `useState` runs asynchronously.

# Functional update
* Use a functional update way instead of the one to do directly if you wanna access an updated value soon after it's updated by `useState` in the same event(function).

cf. [Reference article(ja)](https://zenn.dev/yuji6523/articles/react-usestate-function-update#%E7%B5%90%E5%B1%80%E3%81%AF%E5%B8%B8%E3%81%AB%E9%96%A2%E6%95%B0%E5%9E%8B%E3%82%A2%E3%83%83%E3%83%97%E3%83%87%E3%83%BC%E3%83%88%E3%82%92%E4%BD%BF%E3%81%88%E3%81%B0%E3%81%84%E3%81%84%E3%81%A6%E3%81%93%E3%81%A8%EF%BC%9F)

```React
const increaseDouble = () => {
  setCount(count + 1); // not done
  setCount(count + 1); // done
  console.log(count) // 1
};
```

1. First `setCount(count + 1)` is called. But `count` is still 0 at this point due to the asynchronous update.
2. Instantaneously, second `setCount(count + 1)` is called. But `count` is still 0 at this point too because 1st `setCount` is not done yet.

* So you can use a functional update to resolve that.

cf. https://ja.react.dev/reference/react/useState#updating-state-based-on-the-previous-state

```React
const increaseDouble = () => {
  setCount(count => count + 1); // done
  setCount(count => count + 1); // done
  console.log(count) // 2
};
```

※ However seems there's no big difference between a functional update and a direct update for the most part except for the case like above.