アソビュー流、SWRの使い方。可読性・保守性の高いhooks活用法

はじめに

アソビュー! Advent Calendar 2022の8日目です。

2019年ごろから基本的にReact hooksを使用しており、REST APIを呼ぶ際も以前紹介したこちらのようにhooksベースで行っています。今回はその中でSWRに着目してご紹介したいと思います。tech.asoview.co.jp

SWRとは?

SWRとはstale-while-revalidateの考えに基づいたデータ取得用のライブラリのことで、stale-while-revalidateは直訳すると「再検証している間は古いまま」というようなニュアンスの意味になります。
公式ドキュメントにも記載されておりますが、APIリクエストがされたら、まずそのAPIのキャッシュを返却し、APIのレスポンスが返ってきたらその最新の取得結果をキャッシュと置換するというのが、一番基本的な機能です。
SWRを使用することでコードの可読性が格段に上がるだけでなく、同一のAPIを呼んでいる別のコンポーネントとキャッシュを共有することができるなどのメリットがあり、アソビューではSWRを使用しています。
その他の特徴は公式ドキュメントをご参照ください。

アソビュー!」でのSWRの活用事例

続いて、そんなSWRをアソビューのプロダクトではどのように使用しているのか、こちらの記事では2つ例をご紹介いたします。

1. データの更新と取得があるUI

アソビュー!」の各商品の詳細ページでは以下の画像のように、タイトル右横と画面下部の購入ボタンの左横にお気に入りアイコンが設置されています。これらのお気に入りアイコンのどちらかをクリックすると、お気に入りの登録or解除処理が走り、もう一方のアイコンにもお気に入りのTRUE/FALSEが反映されます。もしよろしければこちらのプランで動作を確認してみてください。



この動作を実現するのに、SWRの2つの機能を活用しています。

  1. グローバルキャッシュを使用して、同一のkeyの場合にすべてのコンポーネント間でデータを保存および共有する機能(公式ドキュメント)
     SWRでは異なるコンポーネント間でのキャッシュ共有機能がデフォルトで実装されています。おかげでReduxやuseStateとuseEffectを使用した複雑な状態管理のコーディングをせずに済んで可読性や保守性が格段にあがっています。

  2. POST用hooksと併用し、SWRを使った更新処理を実現できるミューテーション機能 (公式ドキュメント
     SWRではmutate機能とPOST用のhooksを併用することで、UXを意識した更新処理を実装することできます。今回ご紹介している例では、お気に入りアイコンがクリックされることで、DBに持っているお気に入り状態を変更するAPIがコールされます。SWRのキャッシュなしでは、その更新APIのレスポンスを待たないとお気に入りアイコンのUIの切り替えができませんが、SWRを使うことでその待ち時間がなくなります。
     実装は以下のサンプルコードのようになっております。

useSWRを使用して、お気に入り状態(TRUE/FALSE)を取得します。
② ①で取得したお気に入り状態でお気に入りアイコンを描画します。
③ お気に入りアイコンがクリックされたら、現在のお気に入り状態を反転した値でmutateを実行し、①のuseSWRの取得結果のキャッシュを更新することでisFavoriteLocalが変更され、お気に入りアイコンの表示が切り替わります。(第2引数をfalseに設定することで再検証をせず、一時的にフロント側で更新したキャッシュの値をお気に入りアイコンの判定に使用しています。)
④ POST用のカスタムhooks (別記事で紹介)からPOST用のメソッドtoggleFavoriteを使用して、DBのお気に入り状態を更新します。
⑤ 再度mutateを実行して、更新した最新状態のDBを参照しに行きます。ここでDBの値で判定するように修正します。つまり、③で変更した値と一緒になることを確認することになります。もし、この再検証のAPI通信がエラーになった場合、お気に入り状態は③での変更前にロールバックされる形になり、画面上は一瞬だけお気に入り状態が変化した後にもとに戻ったように見えます。

2. 無限スクロールのあるリストUI

アソビュー!」のマイページには予約管理画面があり、予約や購入したプランの一覧が表示されます。それらの一覧ページの無限スクロールにuseSWRInfiniteを使用しています。



公式ドキュメントでも紹介されていますが、useSWRInfiniteを使用することで、複雑になりがちなページング処理を宣言的で可読性の高いコードで記述することができます。また、SWRの機能によってページを行き来するときなどにキャッシュを生かしてUXを向上する事ができます。 「アソビュー!」では以下のサンプルコードのようにカスタマイズして実装しています。

① 引数として渡ってきた体験ステータス(「体験前」、「体験後」etc)によってkeyを動的化しています。
② axiosのPOSTリクエスト用にクエリ文字列からパラメータを取得しています。
③ axiosを使用することでaxiosのconfigでtimeoutを設定することができ、アソビューでは大量アクセス時にシステム全体を障害から守るために、フロントエンドのAPI通信にもタイムアウトを設けています。
④ APIコールがエラーになった際にrevalidateに回数制限をもたせ、失敗するリクエストを何度もさせないようにしています。
③と④はともに、以下の記事でも紹介させていただいておりますが、弊社で行った負荷対策の一環として導入したものです。 tech.asoview.co.jp

所感

今回のようなキャッシュを生かしたデータ取得や表示更新のUXを、例えばReduxなどを使って実装するとなると非常に実装コストが高く、保守性が低いソースコードになってしまうと考えられます。SWRを使うことでシンプルに実装できるということで大きなメリットがあると感じます。

おわりに

いかがでしたでしょうか?今回はSWRを使った実装例を2つご紹介いたしましたが、アソビューのプロダクトでは他にもたくさんSWRを使った実装箇所があり、各実装箇所でプロダクトの要件に合わせてカスタマイズしております。
技術の移り変わりの早いフロントエンドの領域ですが、アソビューでは今回紹介したSWRのように、プロダクトの開発に役立つ新しい技術は積極的に取り入れております。また、言語やライブラリ単位でのマイナーチェンジに対応したコードのリファクタリングにも一定時間を用意して取り組んでおります。
そんな我々アソビューの開発にご興味を持っていただけましたら、こちらもご覧になっていただけますと幸いです。
www.asoview.com