Closed3

React オフスクリーン(offscreen)機能 とuseEffectについて

HaruHaru

オフスクリーン (offscreen) 機能 とは

  • Reactに今後追加される機能
  • 新たな非表示の概念の追加

既存の2つの非表示

  1. コンポーネントの破棄(アンマウント)
    • 保持している状態が消えてしまう(stateやスクロール位置)
  2. CSSで非表示にする
    • stateは保持されるが、描画更新の処理が走りつづけるので非効率

新たな オフスクリーン (offscreen) 機能で変わること

見た目は非表示にしつつ、描画更新の優先度を落とすことによりパフォーマンスを最適化する

参照

詳細は公式ブログにて

https://ja.reactjs.org/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.html#offscreen

HaruHaru

useEffectの挙動について

すでにReact 18のstrictモードでは挙動が変更される
詳細はこちら

https://zenn.dev/takeharu/scraps/d14cf9d4239ec4

オフスクリーン機能が追加されるとどうなる?

useEffectが複数回呼ばれることになる。
現状下記だとマウント時に2回のみ。

useEffect(() => {
  console.log('Hello')
}, [])

詳細はまだ公表されていないが、オフスクリーン機能の処理イメージは下記の通り

  1. マウント → useEffect発火
  2. オフスクリーンによる非表示 → useEffect クリーンアップ
  3. オフスクリーンによる表示 → useEffect発火

アンマウント(破棄)されなくても、再度副作用が発火される。

そのため、開発環境でのstrictモードでは複数回発火のためのテストとして、2回useEffectが発火される。
実際は、マウント → アンマウント → 再マウントという挙動でuseEffectが2回発火される。

こちらはあくまでテスト用の処理。
アンマウント(破棄)されなくても、複数回発火される可能性があるので、クリーンアップをしようということ。

HaruHaru

ログ送信のような、クリーンアップができない処理に関して

ページを開いた際に、ログを一回だけ送りたい場合など。
通常通り、下記のような処理で問題なし。

useEffect(() => {
  logVisit(url);
}, [url]);

こちらはオフスクリーン機能でも、ログ送信の概念としては正常。
例えばタブ切り替えで、オフスクリーン機能により表示/非表示が切り替わったタイミングで送信されるのは、期待される挙動のため。

ただオフスクリーン機能は

オフスクリーン機能は、高レベルの機能を実現するための低レベル機能です。startTransition のような React の他の並行レンダー機能と同様ですが、大抵の場合、あなたが直接オフスクリーン API を利用することはありません。代わりに、フレームワークが実装する以下のようなパターンを通じて利用することになるでしょう。

と公式にアナウンスされているため、フレームワークによっては予期せぬ表示/非表示が発生する場合などは今後ありそう。

このスクラップは2023/01/23にクローズされました