React.js バッチ更新の初心者向けガイド


概要



数か月前、私が React を学んでいて、インターネットのディープ ホールに入り込んで、React の理由と方法に関するすべてのメジャー マイナー コンセプトを理解していたときに、React のバッチ更新に出くわしました.
私は、React のこの機能が setState 関数を同期的に呼び出す場合と非同期的に呼び出す場合でどのように異なる動作をするかを学びました.

理解を深めるために、この example を検討してください.
これは、バッチ処理の動作の違い、または最近の動作の違いのより広い側面を操作して理解するための簡単な例です.

React 18 の導入により、デフォルトでより多くのバッチ処理を処理することですぐに効率が向上し、アプリケーションで手動で更新をバッチ処理する必要がなくなります.この投稿では、バッチ処理、以前の機能、および変更点について説明します.

最初にいくつかの定義

バッチ処理



バッチ処理とは、React が複数の状態更新を 1 つの再レンダリングにグループ化して、パフォーマンスを向上させることです.

なぜそんなこと??ちょっと工夫中..



SetState() を使用してクラス コンポーネントの状態を更新でき、フック (つまり、useState()) を使用して関数コンポーネントの状態を更新できます.これらの変更の結果、コンポーネント ツリーの一部が再レンダリングされます.簡単な解決策は、setState() を使用するたびにコンポーネントを再レンダリングすることですが、React イベント ハンドラーまたは同期ライフサイクル メソッド内で setState() への多数の呼び出しが行われる場合、これは非効率的です.

React は、バッチ更新メカニズムを実装して、コンポーネントのレンダリングの数を減らします.その結果、複数の状態変更が 1 つの更新にバッチ処理され、最終的にコンポーネントの再レンダリングが 1 回トリガーされます.

明確さと理解を深めるために、この example をもう一度確認してください.

ちょうど最近の過去の..



React バッチ更新がライフサイクル メソッドやイベント ハンドラーなどの既知の方法で行われる場合、React はそれらをバッチ処理しますが、SetTimeout や Promises などのコールバックで行われる場合はそうではありません.これは、状態を更新するために複数の呼び出しを行う場合、React は呼び出しごとにコンポーネントを再レンダリングすることを意味します.

useState または this.setState を使用してコンポーネントの状態を更新した後、更新に応じてコンポーネントの要素が再レンダリングされます.さらに重要なことは、onClick などの React イベント ハンドラー内で状態を更新するための呼び出しが多数ある場合、React は一度に 1 つずつではなくバッチで更新を行い、コンポーネントが実行するレンダリングの数を最小限に抑えます.



同じクリック イベント内で 2 つの状態の更新が発生した場合、React は常にそれらを 1 つの再レンダリングに結合します.次のコードを実行すると、状態が 2 回設定されているにもかかわらず、React はクリックごとに 1 回しかレンダリングしないことがわかります.


function App() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  function handleClick() {
    setCount(c => c + 1); // Does not re-render yet
    setFlag(f => !f); // Does not re-render yet
    // React will only re-render once at the end (that's batching!)
  }

  return (
    <div>
      <button onClick={handleClick}>Click on me !!</button>
      <h1 style={{ color: flag ? "yellow" : "purple" }}>{count}</h1>
    </div>
  );
}



これにより、不要な再レンダリングの回数が減るため、パフォーマンスが向上します.また、問題やバグにつながる可能性がある状態変数が 1 つしか変更されていない「半完成」状態をコンポーネントが示すことも防止します.

後退: ただし、React は更新をバッチ処理するタイミングについて一貫していませんでした.たとえば、データをフェッチしてから上記の handleClick の状態を更新する必要がある場合、React は更新をバッチ処理せず、2 つの独立した更新を実行します.

React 18 までは、React イベント ハンドラー中のみ更新をバッチ処理しました.デフォルトでは、React は promise、setTimeout、ネイティブ イベント ハンドラー、またはその他のイベント内で更新をバッチ処理しませんでした.

これからのバッチング動作..



ほとんどの場合、React 18 以降、すべての更新は、発生元に関係なく自動的にバッチ処理されます.

自動バッチ処理: これは、タイムアウト、promise、ネイティブ イベント ハンドラー、およびその他のイベントの更新が、React イベントの更新と同じ方法でバッチ処理されることを意味します.これにより、レンダリングされる作業が減り、その結果、アプリのパフォーマンスが向上することが予想されます.




function handleClick() {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
}



これと同じように動作します:

setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
}, 1000);




これも同じように動作します.

fetch(/*...*/).then(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
})



また、これと同じように動作します.

element.addEventListener('click', () => {
  setCount(c => c + 1);
  setFlag(f => !f);
  // React will only re-render once at the end (that's batching!)
});



これが役立つことを願っています.それは私を助けました.あなたと同じプログラマー. 🌟