(このスクリーンショットはReact公式ブログから取得されました)
React 17はすでにRC段階に入っています。公式ブログの声明によると、今回のリリースには重大な更新や新機能はありませんが、記事の中には興味深い情報がいくつかありますので、ここで紹介します。
この記事では、すべてのアップデートを一つ一つ説明するのではなく、注目に値する部分を記録します。
イベントデリゲーションのノードの変更
Reactでは、<button onClick={}>
のようなイベントリスナーを使用する場合、Reactはすべてのイベントリスナーをノード自体ではなくdocument
に配置します。これはイベントデリゲーションと呼ばれるテクニックで、多数のイベントリスナーによるパフォーマンスの問題を回避するためのものです。React 17では、リスナーはドキュメントではなくルートエレメントに配置されます。これはReactが制御下にあるため、将来的には「Replay Event」といった新機能を簡単に追加できるという利点があります。
イベントプーリングメカニズムの削除
パフォーマンスの向上のため、React 17以前では、イベントプーリングメカニズムが使用されていました。これは、独自の「Synthetic Event」という仕組みを実装していました。しかし、公式の説明によると、現代のブラウザでは、その効果は限定的であり、開発者に混乱を引き起こすこともあります。たとえば、e.target
を他のコンポーネントにパラメータとして渡す場合、null
であることに気づくかもしれません。これは、Reactがパフォーマンスを向上させるために行った設計です。正しく使用するには、e.persist()
を追加してReactがそれに干渉しないようにする必要があります。
React 17以降、イベントプーリングメカニズムは完全に削除されましたので、e.persist()
を追加する必要はありません。素晴らしいですね。一部の記事やチュートリアルでは、Reactのイベントプーリング設計が強調されているかもしれませんが、将来的にはその説明を変更する必要があるかもしれません。
星を打つ:useEffectのクリーンアップ関数のタイミング変更
これはおそらく今回の変更の中で最も重要なものです。
useEffect
を使用する場合、ほとんどのeffect
は画面の更新とは関係ありませんので、Reactは画面の更新の後にeffect
を実行します。
全体的なフローは以下のようになります:
コンポーネントの更新 → DOMの対応する変更 → 画面の更新 → effect
の実行
これにより、effect
内で行われる処理が計算量が大きい場合にDOMの描画に影響を与えるのを避けることができます。例えば:
const App = () => {
useEffect(() => {
longlongTask(); // この処理は長い時間がかかります
console.log('Hello World');
})
return <Component />
}
上記のフローにより、Reactは画面の更新後に他のeffect
を実行することで、ユーザーエクスペリエンスを損なうことを防ぎます。
ただし、画面のジャンプを防ぐために画面の更新前にeffect
を実行したい場合は、useLayoutEffect
を使用することができます。
以上がReact 16の予想される動作です。次に、クリーンアップの部分について説明します。
React 16では、useEffect
のeffect
は画面の更新後に実行されますが、クリーンアップ関数は画面の更新の前に実行されます。一般的には、これには影響はありません。ほとんどのクリーンアップ関数は、単にunsubscribe
、リスナーの解除、またはAPIのキャンセルなどの処理です。ただし、クリーンアップ関数が多くの時間を占有する場合、画面の更新に影響を与える可能性があります。
次のように書いた場合を想定してみましょう:
const App = () => {
useEffect(() => {
longlongTask(); // この処理は長い時間がかかりますが、心配しないでください、Reactは画面の更新後に実行します
console.log('Hello World');
return () => {
longlongTask(); // 画面がlonglongTask()の終了までフリーズします(React 16では)
}
})
return <Component />
}
React 16では、クリーンアップの実行タイミングは次のようになります(コンポーネントの更新時):
コンポーネントの更新 → DOMの対応する変更 → クリーンアップ関数の実行 → 画面の更新 → effect
の実行
一方、React 17以降では、クリーンアップのタイミングは画面の更新の後に変更されました(コンポーネントの更新時):
コンポーネントの更新 → DOMの対応する変更 → 画面の更新 → クリーンアップ関数の実行 → effect
の実行
コンポーネントがアンマウントされる場合:
React 16:コンポーネントの更新 → クリーンアップ関数の実行 → DOMの対応する変更 → 画面の更新
React 17:コンポーネントの更新 → DOMの対応する変更 → 画面の更新 → クリーンアップ関数の実行
クリーンアップ関数はuseEffect
の順序に従って実行されます
React 17では、クリーンアップ関数はツリー内の位置に応じて、効果の順序と同じ順序で実行されます。以前は、この順序が時折異なることがありました。
クリーンアップ関数に順序依存性が必要な場合はわかりませんが、React 16では、クリーンアップの実行タイミングが予期しない順序で発生することがありました。