LoginSignup
1
1

Nuxt3で、複数の同一コンポーネント内でほぼ同時にAPIを叩くと結果が同期?された

Posted at

はじめに

Nuxt3で、以下をやろうとしていました。

  • 親コンポーネントでidの配列を持っている
  • それをv-forして子コンポーネントにidを渡しつつ子コンポーネントを複数表示する
  • 子コンポーネントの中でidを引数に取るAPIをコールし、返り値を表示する

このときidごとにAPIの返り値は異なるはずなのですが、表示される結果がすべて同じになってしまいました。
一応解決まで行けたので共有します。

環境

package.json
{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": 省略,
  "dependencies": {
    "nuxt": "^3.10.3",
    "vue": "^3.4.21",
    "vue-router": "^4.3.0"
  }
}

再現するソースコード

./pages/index.vue(親コンポーネント)
<template>
  <div>
    <ChildComponent v-for="id in [1, 2, 3, 4]" :key="id" :id="id" />
  </div>
</template>
./components/ChildComponent.vue(子コンポーネント)
<template>
  <span>{{ userName }}</span>
</template>

<script setup lang="ts">
const { id } = defineProps<{ id: number }>();

const userName = ref<string | null>(null);
useFetch<string>('/api/fetchName', {
  method: 'POST',
  body: { id }
}).then((res) => {
  userName.value = res.data.value || null;
});
</script>
./server/api/fetchName.ts
export default defineEventHandler(async (event): Promise<string> => {
  const { id } = await readBody(event);

  if (id === 1) return 'a';
  if (id === 2) return 'b';
  if (id === 3) return 'c';
  return 'd';
});

上記コードで表示される期待値は以下だが、

abcd

実際は以下になる

dddd

解決方法

理由は分からないですが、以下2点を修正することで解消しました。

  • APIコールをonMounted内で行う
  • それに伴い、useFetchではなく$fetchを使う

修正後のソースコード

./components/ChildComponent.vue(子コンポーネント)
<template>
  <span>{{ userName }}</span>
</template>

<script setup lang="ts">
  const { id } = defineProps<{ id: number }>();

  const userName = ref<string | null>(null);
+ onMounted(() => {
-   useFetch<string>('/api/fetchName', {
+   $fetch<string>('/api/fetchName', {
      method: 'POST',
      body: {id}
    }).then((res) => {
-     userName.value = res.data.value || null;
+     userName.value = res || null;
    });
+ });
</script>

おわりに

解決はしましたが、原因が全く分かっていないので分かるいらっしゃれば教えて頂きたいです。
ライフサイクルの問題か、useFetchの内部処理(キャッシュ等)の問題かと思っていますが...

1
1
2

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