Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Suspenseのユースケースを探る

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 Suspenseのユースケースを探る

Avatar for KeitaroOkamura

KeitaroOkamura

February 08, 2022
Tweet

More Decks by KeitaroOkamura

Other Decks in Technology

Transcript

  1. 知らない方のために • 「Suspense」 は次期メジャーバージョンの React 18 で大きく拡張された機能 ◦ 以前から存在していたが、それまではコンポーネントの Dynamic

    Import のために使われていた • React 18 では Server-Side Rendering (SSR) のストリーミングサポートが追加される ◦ この SSR ストリーミングは Suspense を前提にしている ◦ また、「React Server Components」 という技術的革新においても Suspense(正確に言えば、React Concurrent Rendering という機能)が重要な役割を果たします • つまり ◦ 技術的な転換期に入ってきており(SSG → SSRという流れが強くなっている)様々なステート管理や データ取得ライブラリが Suspense を含む React 18 への対応を始めている ◦ Suspense のおさらいをしないと僕みたいに取り残されますw
  2. Suspense とは何か 簡単に言うと • コンポーネントを「ローディング中なのでまだレンダリングできない」 という状態にすることができるのが Suspense です • Suspense

    というコンポーネントが、内部でレンダリングが失敗したコン ポーネントのハンドリングを担当してくれます ◦ まるで JavaScript の try-catch 文のような振る舞い ◦ React の既存機能である ErrorBoundary と Suspense の仕組みは 似ていて、キャッチする対象が違うだけ ローディング中 <Suspense> </Suspense> キャッチ <ErrorBoundary> エラー </ErrorBoundary> キャッチ
  3. Suspence のユースケース • サスペンスは、データも含むその他あらゆるものを宣言的に「待機」するための機能 ◦ メインのユースケースはデータ取得だが、画像やスクリプト、あるいはその他の非同期的な作業の待機 にも使える ◦ つまり、コンポーネント以外のリソースの取得を待機することができるようになった Suspense

    for Data Fetching is a new feature that lets you also use <Suspense> to declaratively “wait” for anything else, including data. This page focuses on the data fetching use case, but it can also wait for images, scripts, or other asynchronous work. https://reactjs.org/docs/concurrent-mode-suspense.html 公式には以下のように書いてある
  4. 1. コンポーネントが「ローディング中」を宣言する部 分。それは、コンポーネントがレンダリング中に Promise を throw することで行う 2. Suspenseコンポーネント自体。このコンポーネント で囲った部分でサスペンド※が発生した場合、指定

    しているフォールバックコンテンツが代わりにレン ダリングされる ※Promise が解決するまではコンポーネントをレンダリングできない状態 </Suspense> <Suspense fallback={<div>loading…</div>}> <div>loading…</div> Suspense のAPI は主に2つの要素で成り立つ <子コンポーネント /> ローディング中 Promiseをthrowする フォールバックコンテンツを指定 Suspense の仕組み キャッチ
  5. Suspence の仕組み • Promise を投げるのは、それをキャッチした Suspense に「このコンポーネントはいつレンダリングができ るのか」を伝えるため ◦ 投げられた

    Promise が解決されたら、それを投げた子コンポーネントのレンダリングをリトライする という仕組みになっている • render やライフサイクルメソッドでエラーが起きたときに、それを親コンポーネントの componentDidCatch※というライフサイクルメソッドでキャッチするという仕組みで Suspense は動きます ※React で子コンポーネントのランタイムエラーをキャッチするためのハンドラ 詳しく説明すると
  6. • アンマウント ◦ コンポーネントライフサイクルメソッドの一つ => componentWillUnmount() ◦ コンポーネントが DOM から削除されるときに呼ばれる

    • つまり、Suspense によって置き換えられた子コンポーネントは UI が破棄されない ◦ UI が破棄されないので、画面の状態※を残したままにできる ◦ 何度も再描画されてほしくなく、状態を保持したままでいてほしいようなケース ◦ ※どういったケースで使えるのか、実際に実験してみる Suspense によって置き換えられた子コンポーネントは、アンマウントされない Suspense コンポーネントの特徴
  7. • アンマウントされると UI が破棄されるので、入力中の input の値や、スクロール位置などの状態が破棄されてしまう • 同様なケースとしては、タブ切り替えなど • 破棄されるのは

    UI の状態だけ、入力中の値やスクロール位置 を State(コンポーネントによって管理されているオブジェ クト) で管理していれば破棄されない 何が困るか? Suspense のユースケースを探る
  8. • Suspense を利用したコンポーネントを作ってみる • このコンポーネントの中身は、props で受け取った値に応じ て空の Promise を throw

    するというシンプルな中身 ◦ Loadable が ローディング中であることを Promise を throw することで Suspense に伝える ◦ Suspense は その Promise を監視する ◦ fallback は指定しなかったら何も表示されない Promise を throw すればいいってことはわかった Suspense を使ってみる
  9. • アンマウントされないことで、ある瞬間にユーザーから見えない部分について、不要な再レンダリングを回避で きる ◦ つまり、結果として React が不要な計算(Reconciliation のような差分検出処理)をするのを省くことが できる ◦

    今回の実験したケースでは、DOM自体が大きくないので、そこまでパフォーマンスに影響はないかもしれ ない(一つのコンポーネントで管理する派の人たちもいるはず) • しかし、忘れてはいけない制限として ◦ Suspense で囲った子コンポーネントは 一時的に画面から削除され、プレースホルダーに置き換えられる ◦ つまりは、通常はユーザーに表示されないような部分があるケースのみ、Suspense の性質を利用するこ とができる UI を保持すること以外にもうまみがある Suspense のうまみ
  10. • 最もふさわしいユースケースはネイティブアプリの Stack 型のナビ ゲーション ◦ このSuspenseの性質を利用することで Stack の一番上にある コンポーネント以外を停止することで、効率良く画面の状態

    をロックすることができる • React Native の contributor の人が React Native 向けにコンポー ネント作ってました ◦ https://github.com/software-mansion/react-freeze それネイティブアプリじゃん 通常はユーザーに表示されないような部分があるケース
  11. • Suspenseはデータ取得以外のユースケースにも活用できる • Promise を throw すること自体は難しくないが、非同期のデータ取得(データフェッチ系)が絡むと 一から書くのは難しそう ◦ そこは素直にライブラリ使ったほうがいいと思う

    • Suspense を使うことで、今までは ローディング の状態を判定して処理をしていたような、手続き的 なコードがより宣言的に書けるようになる • Suspense によって今までのコンポーネントの責務が大きく変わっていきそう(コンポーネントがロー ディング中の表示の責務を持たないとか) まとめ
  12. 参考 • React 18に備えるにはどうすればいいの? 5分で理解する ◦ https://qiita.com/uhyo/items/bbc22022fe846fd2b763 • ReactのSuspense対応非同期処理を手書きするハンズオン ◦ https://zenn.dev/uhyo/books/react-concurrent-handson

    • Experimenting with React Freeze ◦ https://blog.swmansion.com/experimenting-with-react-freeze-71da578e2fa6 • ソースコード ◦ https://github.com/KeitaroOkamura/suspense-usecases