🌀

SWRを使ってPOSTやDELETEリクエストをすると通信状態が取得できて便利

2024/06/18に公開

SWRとは

「データ取得のための React Hooks ライブラリ」と書いてあります。
https://swr.vercel.app/ja

データ取得のためって書いてるけどGETリクエスト以外でも使える?

v2で加わったuseSWRMutationを使えば出来ます。
https://swr.vercel.app/ja/docs/mutation#useswrmutation

GETリクエスト以外でSWRを使うメリットは?

fetch APIやaxiosを使えばPOSTやDELETEリクエストをすることが可能なので特に使っていなかったのですが、useSWRMutationを使えば、通信中かどうか、楽観的更新、ロールバックなどがサポートされているので便利です。どれもそこまで頻繁に使うケースはないのに、自前で実装すると不具合がないか不安になる機能ばかりです。
タイトルにある通り、useSWRMuationの返り値にあるisMutatingを使えば、リクエストを送ってからレスポンスが変えてくるまでの状態を取得することができます。

 const { trigger, isMutating } = useSWRMutation(
    "https://example.com/user",
    sendRequest
  );
// isMutatingがtrueなら通信中、falseなら通信していない

自分で書くとuseStateで状態管理し、リクエスト開始時に値変更、終了時または失敗時に値を戻すような処理を書くことになるので便利です!

レスポンスが返ってくる前に同じkeyを使ってリクエストをした場合に重複排除されないか?

useSWRMutationをリモートのデータを更新する上で不安だったのは、連続してリクエストを送った場合に重複排除が働き、最後のリクエストがキャンセルされないかでした。

例えば保存ボタンが存在しない、ユーザーが操作するたびにリクエストを送るような画面では、色々操作して最後に画面上に表示されている状態とリモートのデータを一致させたいです。ユーザーが連続で操作できるようにレスポンスが返ってくるまでスピナーを出して待たせるようなこともしたくないので、是非とも連続でリクエストを送りたくなります。

ドキュメントを読んでもはっきりと書いてある箇所がなかったので簡単に検証してみました。

検証内容

究極にシンプルなコードです。上から順番に

  • GETリクエストを送るuseSWR3つ。3つとも同じエンドポイントをkeyとしています
  • POSTリクエストを送るuseSWRMutation1つ
    ※ 検証用のサーバーはmswを使っています
    https://mswjs.io/
import useSWRMutation from "swr/mutation";
import "./App.css";
import useSWR from "swr";

const fetcher = (url: string) => fetch(url).then((r) => r.json());

async function sendRequest(
  url: string,
  { arg }: { arg: { username: string } }
) {
  return fetch(url, {
    method: "POST",
    body: JSON.stringify(arg),
  }).then((res) => res.json());
}

function App() {
  const { data: data1, isValidating: isValidating1 } = useSWR(
    "https://example.com/user",
    fetcher
  );
  const { data: data2, isValidating: isValidating2 } = useSWR(
    "https://example.com/user",
    fetcher
  );
  const { data: data3, isValidating: isValidating3 } = useSWR(
    "https://example.com/user",
    fetcher
  );

  const { trigger, isMutating } = useSWRMutation(
    "https://example.com/user",
    sendRequest
  );

  return (
    <div>
      <div>
        <span>data:{data1?.firstName}</span>
        <span>{isValidating1 ? "GET Validating1" : "Done"}</span>
      </div>

      <div>
        <span>data2:{data2?.firstName}</span>
        <span>{isValidating2 ? "GET Validating2" : "Done"}</span>
      </div>

      <div>
        <span>data3:{data3?.firstName}</span>
        <span>{isValidating3 ? "GET Validating3" : "Done"}</span>
      </div>

      <button onClick={() => trigger({ username: "sample" })}>Click me</button>
      <div>{isMutating ? "POST Mutating..." : "Done"}</div>
    </div>
  );
}

export default App;

検証結果

useSWR

3つのuseSWRは重複排除がされており、リクエストは1件しか発生していません。せっかくなので検証しておきました

useSWRMutation

ボタンをクリックするとPOSTリクエストを送るようにしています。連打してレスポンスが返ってくる前に次のリクエストを送っても、重複排除されることなくリクエストが送られていました!
(紛らわしいのですが最後のリクエストはuseSWRのGETリクエストです)

終わりに

私の場合リモートデータを更新するリクエストを送るのはform要素を使っていることが多く、レスポンスが返ってきたかどうかの判別はフォームライブラリの機能で出来るのであまり気にすることはなかったのですが、useSWRMutationを使えば特に追加のコードを書かずに使える事がわかりました。

SWRのタイトルにデータ取得のための React Hooks ライブラリとデカデカと書いてあるので不安でしたが、useSWRMutationのサンプルコードでも「Update User」と書いてあり、POSTリクエストを使ったデータ取得処理ではなく、更新処理を意図していると思われるので、ライブラリの意図した通りの使い方ではないかなと思っています。

検証で使用したコードはこちらです。
https://github.com/tatsuya-asami/useSWRMutation-POST

コミューン株式会社

Discussion