0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

<Suspense>を再履修する

Posted at

Suspenseを久しく使っていないので、再履修しておこうと思います。
公式 : Suspense


そもそもサスペンスの意味は?

宙ぶらりんの状態、あやふや、どっちつかず、不安、気がかり、持続的緊張感、はらはらする状態
weblio

(サスペンス映画とか言われますね。)

Suspense

<Suspense> を使うことで、子要素が読み込みを完了するまでフォールバックを表示させることができます。

なるほど、子要素が重い時、読み込みに時間がかかる時にSuspenseを使って別の何かを出すことができるということですね。

propsは2つ

  • children
    • レンダーしようとしている実際の UI (コンポーネント)
  • fallback
    • childrenのレンダーが完了するまで代わりにレンダーされるもの。
      • ローディングスピナやスケルトン
// 実装イメージ
<Suspense fallback="ローディング">
  <SomeComponent />
</Suspense>

注意点

React は、初回マウントが成功するより前にサスペンドしたレンダーに関しては、一切の state を保持しま〜...

長いですね、、つまり下記の4つです。

初回マウント前のサスペンド

コンポーネントが初回マウント前にサスペンドすると、Reactはその時点のstateを保持せず、再度レンダリングを最初からやり直します。

// Suspenseのchildren
const SomeComponent = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchData().then(setData);
  }, []);

  if (!data) {
    // 一旦ここまで処理は進むけど、サスペンドが発生。再レンダリングされる。
    // 次のレンダリングはデータの取得を待ってからとなる。
    throw new Promise(resolve => setTimeout(resolve, 1000));
  }

  return <div>{data}</div>;
}

サスペンドとフォールバック

一度表示されたコンテンツが再度サスペンドした場合、通常はフォールバックが再び表示されます。ただし、この更新がstartTransitionやuseDeferredValueによって引き起こされた場合はしません。

レイアウトエフェクトのクリーンアップ

サスペンドによってコンテンツが隠された場合、Reactはレイアウトエフェクトをクリーンアップし、再表示時に再実行します。無駄なDOM操作はしないよということです。

最適化

Reactには、サスペンスと統合された自動的な最適化(ストリーミングサーバレンダリングや選択的ハイドレーション)が含まれています。

使用方法

<Suspense fallback="ローディング">
  <SomeComponent />
</Suspense>

子要素がすべて読み込まれるまで、フォールバックを表示します。

補足

サスペンスコンポーネントをアクティブ化できるのはサスペンス対応のデータソースだけです。これには以下が含まれます~...

つまり、 サスペンス対応のフレームワークしか使えないよ ということです。
Next.js, Remix, Relay は使えるみたいですね。
(useSWRやuseQueryを用いれば、フレームワーク問わず使えます)

コンテンツを一度にまとめて表示する

デフォルトでは、サスペンス内のすべてのツリーはひとつの単位として扱われます。例えば、以下のコンポーネントのうちどれかひとつでもデータ待ちでサスペンドしていれば、すべてがまとめてローディングインジケータに置き換わります。

ということは、Suspenseに巻き込みたくないコンポーネントは、<Suspense>の外に出しておくのが良さそうですね。
非同期するコンポーネントが複数ある場合、準備が出来たものから表示したいのですが...。

ネストされたコンテンツをロード順に表示する

Suspenseの中にSuspenseを入れる...で、できるみたいです。
下記の実装では <Biography><Albums> はそれぞれ準備でき次第表示されます。

// 公式から引用
<Suspense fallback={<BigSpinner />}>
  <Biography />
  <Suspense fallback={<AlbumsGlimmer />}>
    <Panel>
      <Albums />
    </Panel>
  </Suspense>
</Suspense>

新しいコンテンツのロード中に古いコンテンツを表示する

入力するたびにfallbackが表示されてしまうのは良くありません。
次の情報の準備が整うまで、1つ前の情報を出しっぱなしにしたいですね。

useDeferredValue フックを使うことで遅延されたバージョンのクエリ文字列を下に渡すことができます。(useDeferredValueのドキュメントも見ておかないと

download.gif

終わりに

本日は <Suspense>を再履修しました!
非同期データの読み込み中にユーザーにフォールバックUIを提供し、ローディングスピナーやプレースホルダーを表示することで、UIが空白にならないようできます!
ユーザーが「今何を待っているんだろう...」と不安にならないよう、状態を可視化してあげることがとても大事ですね。

Reactでの開発を進める際には、適切な場所で<Suspense>を使って、アプリケーションのパフォーマンスとユーザーエクスペリエンスを最適化しましょう!

合わせてstartTransitionと、useDeferredValueもまた学んでおきましょう〜!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?