React 18について 知っておくべき事
最近ではReact 18がリリースされたばかりです。
React 18は2022年3月29日にリリースされました。
当ブログでは知っておくべき必要のあるすべてを解説していきます。
このリリースでは、いくつかの明確で根本的な変更を加え、これらには内部での重要な変更と多くの新しいAPIが含まれております。
React 18はこの新しいバージョンに更新するために必要なコードの変更は1つだけです。
それでもいくつかの既存の新しい概念が導入されています。
変更点と新機能
npx create-react-app react-18
これにより、最新のReact 18バージョンが自動的にインストールされます。
index.jsファイルにアクセスすると、レンダリング構文にわずかですが今までと違う変化が見られます。
import React from 'react'; import ReactDOM from 'react-dom'; import 'index.css'; import App from './App'; ReactDOM.render( <React.ScriptMode> <App /> </React.ScriptMode>, document.getElementById('root') );
import React from 'react'; import { createRoot } from 'react-dom/client'; import 'index.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.ScriptMode> <App /> </React.ScriptMode> );
React 18では、ReactDOM.renderはReactDOM.createRootに置き換えられます。
createRootはなんなのか
これは、アプリのルートを作成するために使用され、renderメソッドを呼び出してルートをレンダリング致します。
同時実行レンダリング用のメカニズムの一部であり、アクティブな同時レンダリングに使用されrootを生成する為に呼び出すものです。
そしてReactは1つの重要な新しい概念を導入しました。
並行レンダリングとなります。
React v18 同時レンダリング
React 18の最初のアップデートは並行性となっております。
Reactエコシステムの主要部分である同時実行アルゴリズムがあります。
React 18には、現在の並行タスクを中断し後で再開できる機能が含まれます。
以前では並行レンダリングタスクが開始されると、実行が終了するまでそれを停止する方法はありません。
これは単一の同期タスクでもあり、同期タスクは1つずつ実行されるのが以前でのReactでした。
つまりこの同時実行メカニズムが改善され、Reactがレンダリングを中断できるようになったという事になります。
レンダリングが中断された場合でもUIが一貫して表示されることを保証し、UIは大きなタスクをレンダリングしているときでも、ユーザー入力にすぐに応答が可能となります。
並行レンダリングは、サスペンス、ストリーミングサーバーレンダリング、並行レンダリングを利用したトランジションなどのいくつかの新機能をもたらします。
これはReactのコアレンダリングモデルの基本的なアップデートとなっています、ですがこれは裏側で処理されるため、高度な理解のみが貴方に必要となっています。
並行モードはまだ実験的な機能でもあり、React APIの他の部分にこれから少しずつと適応されていきます。
React 18とともに、ユーザーがReactの同時レンダリング機能を最大限に活用できるようにするいくつかの新しいAPIを提供しました。
• useTransition
• useDeferredValue
• useId
• useSyncExternalStore
• useInsertionEffect
これら5つの新しいAPIのユースケース、それらが解決する問題や追加された理由、およびそれらが並行レンダリングの領域にどのように統合されるかについてまずは先に解説を致します。
新しいAPIはすべて並行レンダリングに関連しているため、まずは最初に概念とReactチームがそれに重点を置いている理由をよく理解しておくことを強くお勧めします。
useTransitionフック
useTransition()は移行の為のフックとなります。
遷移状態と遷移を開始する関数を返します。
つまりReactでの状態の更新では、クリック・ドラッグなどの直接やり取りを反映したり、UIをとあるビューから他のビューに移行させたりなどです。
これらを高速更新し遷移および(低速更新)が増加します。
なのでUXが壊れていると感じないように、移行の更新よりも緊急の更新を優先できるようになりました。
この機能を使用するために、ReactはstartTransitionAPIを作成し、どの更新がより高い優先度/緊急性であるか、どの更新が移行であるかをReactに通知致します。
useDeferredValueフック
useDeferredValue(value)の値を受け入れ、更新を延期する値の新しいコピーを返すフックとなります。
以前の値は、更新が完了するまで保持され新しい値がレンダリングされます。
このフックは、debounceまたはthrottleを使用して更新を延期をさせる事に似ております。
useIdフック
基本的にWebアプリケーションの場合、一意のIDが必要な時があります。
例えば< label for="" >、属性はそれらを関連する要素であるforの属性と等しくなければなりません。
useId()では一意のIDを生成するフックとなります。
このフックで生成されたIDはアプリケーション全体で一意となります。
IDにプレフィックスやサフィックスを追加して、コンポーネントで使用される複数の一意のIDを生成ができます。
useSyncExternalStoreフック
useSyncExternalStoreは外部データソース(ストア)からの読み取りとサブスクライブに推奨されるフックとなります。
このメソッドは3つの引数を受け入れます。
const state = useSyncExternalStore(subscribe、getSnapshot [、getServerSnapshot]);
• subscribe
ストアが変更されるたびに呼び出されるコールバックを登録する関数となります。
• getSnapshot
ストアの現在の値を返す関数となります。
• getServerSnapshot
サーバーレンダリング時に使用したスナップショットを返す関数となり、これはオプションのパラメータになります。
useInsertionEffectフック
このフックはuseLayoutEffectフックと非常によく似ております。
useLayoutEffectが抱えていた問題は、レイアウトの読み取りとスタイリングルールの挿入の両方に同じフックが使用されることです。
これにより、1度のパスでレイアウトを複数回計算したり、誤ったレイアウトを読み取ったりするなど、あまり望ましくない動作が発生する可能性があります。
それを対処する為にReactチームはこの新しいuseInsertionEffectフックを導入しました。
前述した通りuseLayoutEffectフックと似ておりますが、違いはDOMノードの参照にアクセスする事ができません。
これはスタイリングルールを挿入することのみを表します。
レイアウトを読み取る前に、スタイルをDOMに挿入する目的のために使用されます。
『useInsertionEffect css-in-js』ライブラリの作成者に限定することを目的としています。
• useLayoutEffect
• useEffect
• useInsertionEffect
これらは2度呼ばれます。
React 18のリリースによって、StrictMode厳密な効果モードと呼ばれる追加の動作が得られます。
厳密な効果が有効になっている場合、Reactは開発モードで新しくマウントされたコンポーネントに対して意図的に効果を二重に呼び出します。
興味深いことに、2回呼び出されることはありません。
本番モードではアプリが1回だけマウントされることを確認できます。
基本的にReact 18でアプリを適切に移行するには、厳密モードを有効にしてみてください。
厳密モードでは、開発中のコンポーネントで何が起こっているかがすぐに分かり、コンソールの不規則性が出力されます。
厳密モードを有効にしても、本番ビルドには影響もないので安心です。
これら新しい5つのフックの扱い方は、今後に個別に記事として取り上げます。
新機能についてもう少しお付き合い下さい
自動バッチ処理
ReactはReact 18に自動バッチ処理を導入しています。
Reactのバッチ処理とは?
Reactがコンポーネント内で行った更新をバッチ処理することを意味します。
バッチ処理により、コンポーネントの不要なレンダリングが防止されます。
以前のReact 17ではすでにバッチ処理を処理しています。
しかし、ブラウザイベントハンドラーおよびフックのバッチに限定されています。
ですので状態の更新は非同期操作でのみ発生しました。その結果、ネイティブイベントハンドラーはバッチ処理されませんでした。
React 18では、promiseやsetTimeout関数などのすべてのマイクロタスク内で箱から出して、自動バッチ処理を行えるので、すべての状態更新のバッチ処理が可能になります。
素晴らしい改善点の機能ですが、もちろんですがこの自動バッチ処理を停止させなければいけない場合もあります。
それを防ぐ為にReactは、特定の状態の更新に対して再レンダリングをトリガーできる、react-dom で指定されたメソッドを提供してくれています。
flushSync()メソッドとなります。
使用方法はインポートしてイベントハンドラー内でメソッドを呼び出し、状態の更新を本体内に配置してあげるだけとなります。
import {flushSync} from'react-dom'; const handleClick = () => { flushSync( () => { setClicked(!clicked); }); setCount(count + 1); };
サーバー上のサスペンス
React 18では、サーバー側にサスペンスを導入しました。
サーバーサイドとは何か、およびサーバーサイドがどのように機能するかについて少し概要を説明致します。
Webページをロードする方法は基本的に2つあります。
クライアント側レンダリング(CSR)と呼ばれるクライアント側、またはサーバー側レンダリング(SSR)と呼ばれるサーバー側のどちらかです。
CSRはJavaScriptに大きく依存しており、データを動的にロードするため、ロード時間が遅くなる傾向があります。
この問題を解決するために、サーバー側のレンダリングを使用して、ページを一度にロードしUXを向上させ、ページをインタラクティブにする時間を短縮致します。
ですがReactではデータのロードを待機している間、ページが応答しなくなります。
それはなぜ?
コンポーネントそのものがレンダリングの準備がまだできていないことを意味します、これはデータまたはコードが欠落している可能性があるという事です。
これを処理するために、React 18ではサスペンスを導入致しました。
Suspenseを使用すると、アプリの遅い部分をSuspenseコンポーネントでラップが可能です、これによってReactに重いコンポーネントのレンダリングを遅らせるように指示が可能となります。
まずは最も軽いコンポーネントが最初にロードしキャッチされるのでUXがその過程で妨げられることはありません。
まとめ
React 18で最も期待されている機能は、同時レンダリング機能となります。
内部では多くの変更をもたらします。
チームの発表により、ユーザーがユースケースに基づいて同時レンダリング機能を採用できるようにする新しいAPIを受け取りました。
デフォルトでより多くのバッチ処理を含む、すぐに使用できるパフォーマンスの向上をもたらします。
これにより、アプリケーションまたはライブラリコードで更新を手動でバッチ処理する必要がなくなり自動でバッチ処理されます。
React Suspense APIは同時レンダリング用に再実装され、サーバーレンダリングを改善できるようになりました。
React 18の完全な変更ログはGitHubで読むことがでできますので是非確認してみて下さい。
本日は以上となります。
最後まで読んで頂きありがとうございます。
この記事が皆様のお役に立てば幸いです。