💨

【Nuxt3】useFetchの誤った使い方

2024/09/02に公開

動作確認環境

  • Nuxt 3.13.0

useFetch の警告

Nuxt 3 で API 呼び出しに便利な useFetch (または useAsyncData) ですが、バージョンアップした際に、ボタンクリック等のイベントハンドラで呼び出そうとすると警告が出るようになりました。

alt text

nuxt3 のドキュメントにも少しだけそのことに触れられており、ドキュメントで紹介されている動画useFetch の誤った使い方について説明されていたので備忘録としてまとめます。

誤った使い方の例

以下は動画内で使われていた例の簡易版です。
簡易なログインフォームで、ユーザー名とパスワードを入力してログインボタンを押すと useFetch を実行します。

<script setup lang="ts">
const userName = ref("");
const password = ref("");
const body = computed(() => ({
  userName: userName.value,
  password: password.value,
}));

const onSubmit = async () => {
  const { error } = await useFetch("/api/login", {
    method: "POST",
    body,
    onResponse() {
      callCount.value++;
    },
  });
};
</script>

<template>
  <form class="form" @submit.prevent="onSubmit">
    <input type="text" placeholder="userName" v-model="userName" />
    <input type="text" placeholder="password" v-model="password" />
    <button>Login</button>
  </form>
</template>

useFetch はリアクティブ値を監視するため、その値に変更がなされるたびに再リクエストを実行します。
そのため、ログインボタンをクリックした時だけ実行してほしいところ、こちらの例では一度onSubmitを実行した後に userName と password の値が変更される度に再リクエストが実行されてしまいます。

alt text

※stackblitz に例と同じような環境を用意したので、実際に動かしたい人は使ってみてください。
https://stackblitz.com/edit/nuxt-starter-yklftb?file=app.vue

解決策 1

warning にもあるように、$fetch はリアクティブデータの監視はないため、警告に従い $fetch を使用すればイベント時にのみリクエストを実行できます。

const onSubmit = async () => {
  const { error } = await $fetch("/api/login", {
    method: "POST",
    body,
    onResponse() {
      callCount.value++;
    },
  });
  if (!error.value) {
    didItWork.value = true;
  }
};

解決策 2

useAsyncData でラッパーしている等の理由で $fetch に変えたくない場合は、setup()のトップレベルで宣言し、refresh()execute() をイベントハンドラで呼び出せば再リクエストが勝手に送られません。

<script setup lang="ts">
const { execute } = await useFetch('/api/login', {
    method: 'POST',
    body,
    onResponse() {
      callCount.value++;
    },
    immediate: false, //即時実行を無効にする
    watch: false // リアクティブデータの監視・再リクエストを無効にする
});

const onSubmit = async () => {
    await execute();
    ...
};
</script>

正直watch:falseを設定すれば監視をストップできるので、トップレベルで宣言せずともリアクティブイベント内で呼び出しても動作上問題なさそうですが、 useFetch の強みはリアクティブデータを監視してくれることなので、「それを無効にするなら$fetch 使ってね」という方針なのかなと推測しています。

GitHubで編集を提案

Discussion