【React】SWRを便利に扱う自作メソッド

# はじめに
今回は、ReactでAPIのfetchを簡単に行える[SWR](https://swr.vercel.app/ja)を、もうちょっと便利に扱う自作メソッド等をご紹介します。

「もっとこんなやり方があるよ！」等の意見がありましたら是非コメントにお願いします!🙇🏻‍♂️🙇🏻‍♂️

## 本題
もっとも基礎的・シンプルな`SWR`の使い方に、以下のようなコードがあります。
以下はユーザーのprofileデータをapiからfetchしてくるカスタムフックです。

```tsx
const useProfile = () => {
    const headers = {
        "Content-Type": "application/json",
        Authorization: `Bearer ${localStorage.getItem("token")}`,
    };
    const url = `${API_URL}/profile`;

    const fetcher = async () => {
        return axios.get(url, { headers }).then((response) => {
            return response.data;
        });
    };

    const { data, error, isLoading } = useSWR<Profile>(url, fetcher);

    return { data, error, isLoading };
};
```

これでも十分にシンプルだとは思いますが、`headers`や`fetcher`に関しては使い回しがかなり効くので切り出してしまいましょう。

例えば以下はそれらを切り出してみた例です。

```ts
const swrFetcher = async (url: string) => {
    const headers = {
        "Content-Type": "application/json",
        Authorization: `Bearer ${localStorage.getItem("token")}`,
    };

    const response = await axios.get(url, { headers });
    return response.data;
};

const useProfile = () => {
    const url = `${API_URL}/profile`;

    const { data, error, isLoading } = useSWR<Profile>(url, swrFetcher);

    return { data, error, isLoading };
};
```

こうしておけば、他のフックを作成する時に`swrFetcher`をimportして使用するだけなので、書くのが多少楽になります。

また、`SWR`にはデータの更新タイミング等を制御できる機能があります。
以下は、"初回のfetch以降、そのキャッシュを使い続ける"というoptionを付与した`useSWR`です。
(`useSWRImmutable`という同等の機能を持つフックがありますが、説明のため`useSWR`を使用します)

```ts
const useProfile = () => {
    const url = `${API_URL}/profile`;

    const { data, error, isLoading } = useSWR<Profile>(
        url,
        swrFetcher,
        {
            revalidateIfStale: false,
            revalidateOnFocus: false,
            revalidateOnReconnect: false,
        }
    );

    return { data, error, isLoading };
};
```

この時第三引数部分を切り出しておくと、コードが簡潔になり同じオプションを他で使いたい時便利になります。

```ts

const swrConfig = {
    // 初回のfetchのみ行い、以降はキャッシュを返すoption
    Immutable: {
        revalidateIfStale: false,
        revalidateOnFocus: false,
        revalidateOnReconnect: false,
    },
};

// 〜〜〜省略〜〜〜
    const { data, error, isLoading } = useSWR<Profile>(
        url,
        swrFetcher,
        swrConfig.Immutable
    );
// 〜〜〜省略〜〜〜
```

コメントを書いておけばどういったオプションなのか一瞥しただけでわかりますし、こうすることで再利用しやすくなります。

:::note info
大変ためになるコメントをいただいたので、以下その内容を追記させていただきます。
:::

ここまでの内容をまとめると、コードは以下の状態です。

```ts
const swrFetcher = async (url: string) => {
    const headers = {
        "Content-Type": "application/json",
        Authorization: `Bearer ${localStorage.getItem("token")}`,
    };

    const response = await axios.get(url, { headers });
    return response.data;
};

const useProfile = () => {
    const url = `${API_URL}/profile`;

    const { data, error, isLoading } = useSWR<Profile>(
        url,
        swrFetcher,
        swrConfig.Immutable
    );

    return { data, error, isLoading };
};
```
ここから更にコード量を減らし、楽に共通化できます。

axiosの機能に`create`というものがあります。
これはインスタンスを作成するメソッドで、使用することにより`baseURL`や`headers`を変更したインスタンスを使用することができます。これを適用したコードは以下のようになります。

```ts
const instance = axios.create({
  baseURL: 'http://localhost:3003/api', // 先程までのAPI_URLにあたる部分
  headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${localStorage.getItem("token")}`,
    },
});

const swrFetcher = async (url: string) => {
    const response = await instance.get(url); // 上で作成したインスタンスを使用
    return response.data;
};

const useProfile = () => {
    const url = "profile";

    const { data, error, isLoading } = useSWR<Profile>(
        url,
        swrFetcher,
        swrConfig.Immutable
    );

    return { data, error, isLoading };
};
```

キーにも使用しているurlがかなりシンプルになり、`swrFetcher`も二行で済むものになりました。

同じくaxiosの、`interceptors`機能を使うことで同じような省略ができます。
これらは個人の好みや、やりたいことに対してどれだけ合っているかで選ぶ感じでしょうか。

https://axios-http.com/ja/docs/interceptors

## おわりに
共通化できる部分はどんどん切り出していくとコードが見やすくなって良いんじゃないでしょうか🤗
SWRについて、またコードの書き方についてのコメント是非ともお願いします🙇🏻‍♂️

お読みいただきありがとうございました！