Nuxt3 – useFetch / useAsyncData / fetch – リクエスト対象のURLやパラメータを変えて再リクエスト出来るのか？

# まとめ

- `useFetch` のオプションにリアクティブな値を与えておくと、値が変わった時に自動的に再リクエストしてくれるようだ
- `useFetch` で リクエスト先のURLをリアクティブに変えることは出来ない気がした 
- `$fetch` か `useAsyncData` であれば URL自体も変えながら動的にリクエストが出来る

# useFetch でオプションの値をリアクティブにする

オプションにリアクティブな値を渡すことが出来て、値が変わった場合には自動的に再リクエストしてくれる

>All fetch options can be given a computed or ref value. These will be watched and new requests made automatically with any new values if they are updated.

https://nuxt.com/docs/api/composables/use-fetch

## ファイル例

```vue
<script setup lang="ts">
const fetchURL = ref('https://httpbin.org/get')
const query = ref({ x: self.crypto.randomUUID() })

const { data } = await useFetch(fetchURL.value, {
  query: query,
})

function changeQuery() {
  query.value = { x: self.crypto.randomUUID() }
}
</script>

<template>
  <div>
    <button @click="changeQuery">Change Query</button>
  </div>

  <div>
    {{ data }}
  </div>
</template>
```

## 結果例 (Networks)

クエリを変えるたびに別のURLパラメータでリクエストが起こる

<img width="735" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/a4f566fd-4449-4d2c-822d-15ecc6e059b7">


# useFetch -  URLそのものはリアクティブに出来なさそう

## ファイル例


URLの値を変えても何も起こらず、 `refresh` / `execute` しても変更前のURLにリクエストされてしまう

```vue
<script setup lang="ts">
const fetchURL = ref('https://jsonplaceholder.typicode.com/todos/1')

const { data, refresh } = await useFetch(fetchURL.value)

function changeURL() {
  fetchURL.value = 'https://jsonplaceholder.typicode.com/todos/2'
  refresh()
}
</script>

<template>
  <div>
    <button @click="changeURL">Change URL</button>
  </div>

  <div>
    {{ data }}
  </div>
</template>
```

URLまで変わる場合は `$fetch` が良いのかも知れない

https://qiita.com/sameyasu/items/adacceb8a1bee893599b

## 結果例 (Networks)

<img width="752" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/29487765-db4f-4413-9b03-ede98da3a77e">


# $fetch を使う場合の例

URLそのものを変えながら、何度でもリクエスト出来る
(ボタンを押すたびに次の連番のTODOを取得する例)

```vue
<script setup lang="ts">
const result = ref()

const count = ref(1)

const data = await $fetch(`https://jsonplaceholder.typicode.com/todos/${count.value}`)
result.value = data

async function fetchNextTODO() {
  count.value++
  const data = await $fetch(`https://jsonplaceholder.typicode.com/todos/${count.value}`)
  result.value = data
}
</script>

<template>
  <div>
    <button @click="fetchNextTODO">Fetch Next TODO</button>
  </div>

  <div>
    {{ result }}
  </div>
</template>

```

## 注意

SSRの場合 `$fetch` を script 直下で使うと2回リクエストされてしまいそうなので注意

https://nuxt.com/docs/api/utils/dollarfetch

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/e9f00634-408e-4b9f-8a47-50485741f113)


## 結果例 (Networks)

<img width="753" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/bc6f4146-9bb6-4e96-8971-64b3f7c11e78">


# useAsyncData

- useAsyncData は引数に `$fetch` を渡す方式のようだ
- `$fetch` より高レイヤーで `useFetch` より低レイヤーという感じがする (合ってる？)

https://nuxt.com/docs/api/composables/use-async-data

次のように書いても期待通り動作する

## ファイル例

```vue
<script setup lang="ts">
const count = ref(1)

const { data, refresh } = await useAsyncData('todos', () =>
  $fetch(`https://jsonplaceholder.typicode.com/todos/${count.value}`),
)

async function fetchNextTODO() {
  count.value++
  refresh()
}
</script>

<template>
  <div>
    <button @click="fetchNextTODO">Fetch Next TODO</button>
  </div>

  <div>
    {{ data }}
  </div>
</template>
```


## 結果例 (Networks)

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/e13285d1-be3a-4d58-9ffb-99214e04bc29)


# 関連

https://github.com/YumaInaura/YumaInaura/issues/3526