LoginSignup
2
0

【React(TypeScript)】axiosのinterceptorsでuseNavigateを使う

Last updated at Posted at 2023-12-10

概要

axiosでエラーが発生した時にエラー画面に遷移させるとか、axiosのインターセプターでuseNavigateを使いたい時ってありますよね。色々と試行錯誤して、比較的簡単に実現できる方法が分かりましたので、同じように困っている方に向けてマイベストプラクティスとして共有させていただきたいと思います。

やり方

axiosのレスポンスインターセプターをコンポーネント化し、これをReact Routerで有効にします。

axios.ts

axiosのインスタンスを作成し、必要に応じて共通の設定を入れてexportします。

※ここではextendsフォルダ配下に作ったとします。

const axiosClient = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL,
  timeout: 30000,
})

export default axiosClient

AxiosResponseHandler.tsx

axiosのレスポンスインターセプター用にコンポーネントを作成します。(※コンポーネントなのでファイルの拡張子は.tsxにする必要があります)
useEffect()を使ってaxiosのレスポンスインターセプターを設定します。コンポーネントになっているのでuseNavigateなどのReact Hooksを自由に使うことができます。
useEffectの処理は非同期で行われるのでInterceptorがうまく設定できないことがあるためisSetというState変数を作って確実に設定されるように制御します。
returnは引数のchildrenをそのまま返すようにします。

import axios from 'extends/axios'

type Props = {
  children: React.ReactNode
}

export const AxiosResponseHandler = ({ children }: Props) => {
  const navigate = useNavigate()
  const [isSet, setIsSet] = useState(false)

  useEffect(() => {
    // リクエストインターセプター
    const requestInterceptors = axios.interceptors.request.use((config) => {
      // 例:共通リクエストヘッダーを付ける
      config.headers['XXXXXXX'] = XXXXX
      return config
    })

    // レスポンスインターセプター
    const responseInterceptors = axios.interceptors.response.use(
      (response) => response,
      async (error) => {
        switch (error.response?.status) {
        
     (省略)

          case 500:
            navigate('error/500')
            break
          default:
            return await Promise.reject(error)
        }
      },
    )
  }, [])

  setIsSet(true)

  // クリーンアップ
  return () => {
    axios.interceptors.request.eject(requestInterceptors)
    axios.interceptors.response.eject(responseInterceptors)
  }

  return <>{isSet && children}</>
}

Router.tsx

BrowserRouterとRoutesの間にAxiosResponseHandlerを入れます。これによりRoutes配下の画面でextends/axiosを使用すれば、AxiosResponseHandlerのaxiosレスポンスインターセプターが有効になります。

const Router = () => (
  <BrowserRouter>
    <AxiosResponseHandler>
      <Routes>
        <Route path="signIn" element={<SingIn />} />

        (省略)
        
      </Routes>
    </AxiosResponseHandler>
  </BrowserRouter>
)

export default Router

(参考) 直接axiosを使うのを禁止する

拡張したaxiosではなく、直接axiosを使ってしまうとインターセプターの処理を通らないので困ったことになります。これを防ぐためESLintを使って直接axiosをインポートするのを禁止します。
ESLintの導入方法についてはここでは触れませんので各自でググってください。

.eslintrc.json

{
  "rules": {
    "no-restricted-imports": [
      "error",
      {
        "paths": [
          {
            "name": "axios",
            "message": "Please import axios from 'extends/axios'."
          }
        ]
      }
    ]
  }
}
2
0
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
2
0