FrontEnd

React QueryのSuspese Modeを使ってみた! [TypeScript]

投稿日:

はじめに

React 18が先日正式リリースされましたね🎉 その中でも、Suspense機能が気になったので調べていたところ、React QueryがSuspenseモードをサポートしていたため、調査して記事にまとめました。

React Suspenseとは

Suspenseとは、データ取得するときのローディング状態を表現できるコンポーネントで、次のような使い方をします。

Issuesはクエリを実行するコンポーネントですが、ローディング中はPromiseがthrowされることによってサスペンド状態となり、代わりにfallbackに指定した内容がレンダリングされる仕組みです。
コンポーネントがサスペンド状態になると、レンダリング自体が行われなくなるため、レンダリングコストの軽減にもつながりそうですね。

ちなみに、Suspense自体はReact 16.6で実験的機能として追加され、React Queryも以前からサポートされていたようですが、React 18で正式版となったことで、使いたい場面が増えてくるかもしれません!

React Queryでは、Suspenseモードを有効化することで、実装できるようになります。Suspenseモードを使わない場合では、useQuery() から data, isLoading, error を取得し、isLoadingやerrorの内容をみてコンポーネントの中身を出し分けるという実装が多かったと思います。
Suspenseモードを使う場合は、ローディング中はPromiseがthrowされ、エラーの場合はJSエラーがthrowされるため、これらの状態によってコンポーネントの中身を出し分ける必要がなくなります。
その代わりに、親コンポーネントでのハンドリングが必要となり、ローディング中はSuspenseコンポーネント、エラーはErrorBoundaryを使って実装します。
それでは、ここからは実装方法を紹介します。

React QueryのSuspense Mode

今回は、React QueryのSuspense Modeを使った実装方法を紹介します。全体のコードはこちらのCodeSandBoxで動かせるようになっています!

事前準備

React Queryのhookを実装します。今回は、Github APIのIssuesを取得するAPIをリクエストするようにしています。

Suspenseモードの有効化

React Queryでは、hook単位でSuepenseモードを有効化する方法と、全体で有効化する方法があります。今回は全体で有効化する方法で実装してみます。
QueryClientの生成時のオプションとして、 suspense: true を設定することでSuspenseモードを有効化できます。

データをフェッチするコンポーネントの実装

GithubのIssueを取得して表示するコンポーネントを実装します。

この実装のポイントとしてはReact QueryでSuspenseモードを有効化すると、 isLoadingerror の面倒を見る必要がなくなります。その代わりにローディング中は、Promiseがthrowされるようになるため、このIssuesコンポーネントをサスペンド状態となり、レンダリングされなくなります。
エラーが発生した場合は、親コンポーネントにエラーがthrowされるため、ErrorBoundaryでキャッチする必要があります。

ErrorBoundaryの実装

続いて、ErrorBoundaryを実装します。

このErrorBoundaryは、エラーが発生したときに、クエリを再試行する仕組みを実装しました。この仕組みを紹介します。
Propsで reset: () => void を受け取るようにしています。これは、後ほど実装する親コンポーネントの QueryErrorResetBoundary から受け取れる関数がそのまま入るようになっいます。
この reset() 関数は、子コンポーネントで実行された直近のクエリをリセットし、再試行させることができます。

Suspenseの実装

ここからは、Suspenseコンポーネントを使って実装します。

親から順に QueryErrorResetBoundary > ErrorBoundary > Suspense > Issues(クエリを実行するコンポーネント) という親子関係になっている点がポイントです。これらのコンポーネントが実際に動作する流れを説明します。

  • Issuesコンポーネントがローディング中の場合、サスペンドするため、そのfallbackである <h1>loading...</h1> が表示されます。
  • ローディングが完了すると、Issuesコンポーネントがレンダリングされます。
  • エラーが発生した場合は、ErrorBoundaryコンポーネントでキャッチします。
  • QueryErrorResetBoundaryを使うと、エラー発生時に reset() を呼び出すことで、クエリを再試行できます。

おまけ

せっかくローディング状態を実装するので、MUIのSkeltonを使ったUIも作ってみました。

さいごに

React QueryのSuspenseモードを使うと、これまでは各コンポーネントでハンドリングしていた状態を、親コンポーネントに集約することができ、実装がスッキリすることが分かりました。各コンポーネントで同じようなハンドリングを実装している場合は、Suspenseモードの方が効率よく実装できるかもしれませんね!

おすすめ書籍

Reactハンズオンラーニング 第2版 ―Webアプリケーション開発のベストプラクティス プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

blog-page_footer_336




blog-page_footer_336




-FrontEnd
-, ,

執筆者:


comment

メールアドレスが公開されることはありません。

CAPTCHA


関連記事

Vue.jsのコードをTypeScriptで書く

1 はじめに2 TypeScriptでの書き方2.1 定義2.2 data2.3 methods2.4 computed2.5 props2.6 emit2.7 lifecycle hooks2.8 ...

Vue on Rails で作ったアプリを振り返ってみる

1 はじめに2 全体的なこと2.1 ディレクトリ構成2.2 CSSフレームワーク2.3 Capistranoでのデプロイ3 axiosのラッパー4 Vuex4.1 ログインの状態管理5 Router6 ...

Go言語

Go WebAssemblyでPromiseを使って非同期化してみた

1 はじめに2 Go WebAssemblyで非同期化のコード3 Promise化する4 おまけ5 さいごに6 おすすめ書籍 はじめに 先日WebAssemblyに入門して、実際に以下のチュートリアル ...

svelte

Svelteのチュートリアルをやってみた

1 はじめに2 Svelteとは?2.1 Svelteの特徴2.2 Write less code2.3 No Virtual DOM2.4 Truly reactive3 Svelteのシンタックス ...

vuex-module-decoratorsとTypeScriptでvuexをスマートに書く

1 はじめに2 導入3 どのように記述するか3.1 初めに3.2 state3.3 mutation3.4 action3.5 getter3.6 async MutationAction3.7 Dy ...

フォロー

blog-page_side_responsive

2022年4月
 12
3456789
10111213141516
17181920212223
24252627282930

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。