5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactデータ取得&ステート管理ライブラリSWRのオレオレラッパーを作ってみた

Last updated at Posted at 2022-03-12

TL;DR

SWR wrapper

useCustomeSWR.ts
import useSWR, { BareFetcher } from 'swr'
import { PublicConfiguration } from 'swr/dist/types'

import { buildApiClient } from '@/lib/apiClient'

type AxiosOptions = {
  baseUrl?: string
}

const useCustomSWR = <Data>(
  key: string,
  bareFetcher: BareFetcher<Data> | undefined | null = undefined,
  config: Partial<PublicConfiguration<Data, any, BareFetcher<Data>>> | undefined = undefined,
  axiosOptions: AxiosOptions = {},
) => {
  const fetcher = getFetcher<Data>(bareFetcher, axiosOptions)
  return useSWR<Data>(key, fetcher, config)
}

const getFetcher = <Data>(
  fetcher: BareFetcher<Data> | null | undefined,
  axiosOptions: AxiosOptions = {},
) => {
  if (fetcher === undefined) {
    const apiClient = buildApiClient(axiosOptions)
    return (url: string) => apiClient.get(url).then((r) => r.data)
  }

  return fetcher
}

export default useCustomSWR

Axios wrapper

apiClient.ts
import axios from 'axios'

type Props = {
  baseUrl?: string
  headers?: {}
}

export const buildApiClient = ({ baseUrl = 'http://localhost:8080', headers = {} }: Props) => {
  const customHeaders = { ...headers, ...{ 'Content-Type': 'application/json' } }

  const apiClient = axios.create({
    baseURL: baseUrl,
    responseType: 'json',
    headers: customHeaders,
  })

  apiClient.interceptors.request.use(
    (config) => {
      console.log(config)
      return config
    },
    (error) => {
      console.error(error)
      return Promise.reject(error)
    },
  )

  apiClient.interceptors.response.use(
    (response) => {
      console.log(response)
      return response
    },
    (error) => {
      switch (error.response?.status) {
        case 400:
        case 401:
          break
        default:
          console.error(error)
      }
    },
  )

  return apiClient
}

ざっくりSWRとは

データ取得のための React Hooks ライブラリです。
以下のような特徴があり、シンプルかつ高機能なデータ取得から取得データのステート管理までをまるっと行ってくれます。
ref: swr.vercel.app

  • 速い、 軽量 そして 再利用可能 なデータの取得
  • 組み込みの キャッシュ とリクエストの重複排除
  • リアルタイム な体験
  • トランスポートとプロトコルにとらわれない
  • SSR / ISR / SSG support
  • TypeScript 対応
  • React Native

SWRにはglobal configが提供されており、こちらを使用することでuseSWRの処理をカスタマイズすることができますが呼び出し元によって設定をカスタマイズしたいユースケースを考えwrapperを作成し利便性を上げてみました。

ref: swr.vercel.app グローバルな設定

使い方

データ取得で使う

 

useFetchData.ts
import useCustomSWR from '@/lib/useCustomSWR'

type Data = {
  data: { code: number; name: string }[]
}

const useFetchData = () => {
  const { data, error } = useCustomSWR<Data>('/api_endpoint')

  return {
    data,
    isLoading: !error && !data,
    isError: error,
  }
}

export default useFetchData

<Data>のようにtypeを渡すことで返却される data のtypeを定義できるのがポイントです。

APIリクエストしないステート管理で用いる

SWRは第二引数のfetcherにnullを渡すとAPIリクエストをしないようにできるのがポイントです。これとSWRによって提供されているmutateという関数を用いてグローバルステート管理に使えます。
ref: SWRはローカルの状態管理としても使える

useGlobalNotification.ts
import useCustomSWR from '@/lib/useCustomSWR'

const useGlobalNotification= () => {
  const { data: message, mutate: setMessage } = useCustomSWR<string>(
    'notification',
    null,
    {
      fallbackData: "",
    },
  )
  return {
    message,
    setMessage
  }
}

export default useGlobalNotification

一つ目の引数にはglobalStateのkeyとなる文字列を渡し、二つ目のfetcherにnull、三つ目のoptionsにはfallbackDataを渡すことによりデフォルトのステートの値を定義できます。
keyはユニークでないといけないので実際にはenumなどを用いて一つのファイルで定義しておくと良いでしょう。

こちらを各コンポーネントで呼びsetMessageを用いてmessageステートを変更することでmessageステートの参照コンポーネントにレンダリングが走ります。

まとめ

Reactのステート管理ツールには他にもrecoil, react-queryなどがありますが個人的にはSWRがシンプルかつパワフルな機能を提供していてオススメです!試したことない方は是非使ってみてください!

5
1
1

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
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?