1. ホーム
  2. reactjs

[解決済み] Reactはフック使用時に状態更新関数をバッチ処理しますか?

2023-02-13 01:03:06

質問

クラス部品について。 this.setState はイベントハンドラ内であれば一括して呼び出します。しかし、状態がイベントハンドラの外側で更新された場合、どうなるでしょうか。 useState フックを使用した場合はどうなるでしょうか?

function Component() {
  const [a, setA] = useState('a');
  const [b, setB] = useState('b');

  function handleClick() {
    Promise.resolve().then(() => {
      setA('aa');
      setB('bb');
    });
  }

  return <button onClick={handleClick}>{a}-{b}</button>
}

レンダリングは aa - bb をすぐにレンダリングするのでしょうか?それとも aa - b となり、その後 aa - bb ?

どのように解決するのですか?

TL;DR - もし状態変化が非同期でトリガーされた場合(例えばプロミスでラップされた場合)、それらはバッチされません。

これを試すためにサンドボックスをセットアップしてみました。 https://codesandbox.io/s/402pn5l989

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

import './styles.css';

function Component() {
  const [a, setA] = useState('a');
  const [b, setB] = useState('b');
  console.log('a', a);
  console.log('b', b);

  function handleClickWithPromise() {
    Promise.resolve().then(() => {
      setA('aa');
      setB('bb');
    });
  }

  function handleClickWithoutPromise() {
    setA('aa');
    setB('bb');
  }

  return (
    <Fragment>
    <button onClick={handleClickWithPromise}>
      {a}-{b} with promise
    </button>
    <button onClick={handleClickWithoutPromise}>
      {a}-{b} without promise
    </button>
      </Fragment>
  );
}

function App() {
  return <Component />;
}

const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);

2つのボタンを作成しました。1つは、あなたのコード例のようにプロミスでラップされた状態の変化をトリガーし、もう1つは状態の変化を直接トリガーします。

コンソールを見ると、"with promise" ボタンを押すと、まず a aa と表示され b b であれば a aa となり b bb .

ですから、答えはノーです。この場合、レンダリングされないのは aa - bb をすぐにレンダリングするのではなく、状態が変わるたびに新しいレンダリングが開始され、バッチ処理は行われません。

しかし、「約束なし」ボタンをクリックすると、コンソールには a aa と表示され b bb をすぐに使えるようにします。

つまりこの場合、Reactは状態の変更を一括して行い、両方合わせて1回のレンダリングを行います。