ページ遷移の際、実行中のリクエストをキャンセルする

リクエスト中にページ遷移すると、もう必要ないのにバックエンドでは実行中のリクエスト達がひたすら応答を待ち続けていました。 あまり好ましくないのでページ遷移の際にこいつらを駆逐することにしました。

ポイントは3つ!!!

  • リクエストの際、CancelTokenSourceより取得したキャンセル用トークンをAxiosRequestConfigに指定する
  • ライフサイクルフック(lifecycle hooks) でCancelTokenSourceのキャンセル処理を呼び出す
  • キャンセル時、例外がthrowされるためエラーハンドリングしてあげる
<template lang="pug">
el-table(:data="state.tableData")
  el-table-column(prop="bookId" label="Id" width="140")
  el-table-column(prop="bookTitle" label="Title" width="*")
</template>

<script lang="ts">
import { defineComponent, onMounted, onUnmounted, reactive } from "vue";
import axios, {
  CancelToken,
  CancelTokenSource,
  AxiosRequestConfig,
} from "axios";

export default defineComponent({
  name: "BookListPage",
  setup() {
    const state = reactive({
      tableData: [],
    });

    // CancelTokenSourceを生成
    const cancelToken: CancelTokenSource = axios.CancelToken.source();

    onMounted(async () => {
      try {
        // リクエスト時、AxiosRequestConfigにキャンセル用のトークンを設定
        const response = await axios.get("/api/v1/books/", {
          cancelToken: cancelToken.token,
        } as AxiosRequestConfig);

        state.tableData =
          response && response.data && response.data.books
            ? response.data.books
            : [];
      } catch (err) {
        // キャンセルが行われると例外がthrowされるので切り分ける
        if (axios.isCancel(err)) {
          console.log(`cancelによるエラーだよ(${err})`);
        } else {
          console.log(`cancelによるエラーじゃない(${err})`);
        }
      }
    });

    onUnmounted(async () => {
      // 実行中のリクエストをキャンセルする
      cancelToken.cancel("cancelしました");
    });

    return {
      state,
    };
  },
});
</script>