【ゼロから学ぶNuxt3×Typescript】⑦useFetch()、useRoute()を使って動的なページを作る

Nuxt３×TypeScript 学習
下記の参考サイトを見ながら、Nuxt３とTypescriptを学ぶ第7回。

▼　神回|vue3.js nuxt3 typescriptどうやる？【ゼロから解説】

https://field.asia/%E7%A5%9E%E5%9B%9Evue3-js-nuxt3-typescript%E3%81%A9%E3%81%86%E3%82%84%E3%82%8B%EF%BC%9F%E3%80%90%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E8%A7%A3%E8%AA%AC%E3%80%91/


前回はこちら👇

https://qiita.com/sakuc47/items/4ab397e777eb796a86c0

第1回はこちら👇

https://qiita.com/sakuc47/items/2770d40720070b682ee9

前回は、JOBページを作成した。
今回はエラーの解消をしながら、作成した部分を掘り下げて理解する。

・<ins>jobs/index.vue<ins>（前回作成）
```vue
<template>
  <h2>求人一覧</h2>
  <ul>
    <li v-for="job in jobs" :key="job.id">
      <p>求人ID: {{ job.id }}</p>
      <p>求人タイトル: {{ job.title }}</p> <!-- name? -->
      <p>求人内容: {{ job.description }}</p>
      <p>画像：<img :src="job.cover" alt=""></p>
    </li>
  </ul>
</template>

<script lang="ts">
import { ref,reactive} from 'vue'

export default {
  // awaitを使う時は関数の先頭にasyncをつける
  async setup() {
    // ref関数でjobs変数を作成
    const jobs = ref([])
    // await 非同期処理
    // fetch ブラウザのAPIで、HTTPリクエストを発行してデータを取得する
    // APIの中のdataというキーを変数に入れている
    const { data } = await useFetch(`https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs`)
    jobs.value = data._rawValue
    console.log(data._rawValue);
    // const { data: jobs } = await useFetch(`https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs`)
    return {
      jobs,
    }
  }
}
</script>

```

### 1.templateの解説

```vue
<li v-for="job in jobs" :key="job.id">
```

v-forディレクティブを使用して`jobs`配列内の各要素をループする。

▼公式ドキュメント

https://ja.vuejs.org/api/built-in-directives.html#v-for

・key による状態管理

https://ja.vuejs.org/guide/essentials/list.html#maintaining-state-with-key

Vue.jsを使ってリストなどの情報を表示する時、各項目を区別するために一意なキーが必要＝「key属性」を指定する必要がある。

key属性を指定することで、Vue.jsは各項目を追跡でき、情報の追加や削除、順番の変更などがあっても対応することができる。

:::note info
・v-forを使う時はkey属性を指定する
・v-forのkeyにはオブジェクトを入れない
:::

↓公式ドキュメントによると、
> ただし、反復処理する DOM の内容が単純なものである (つまりコンポーネントやステートフルな DOM 要素を含まない) 場合、またはパフォーマンス向上のために意図的にデフォルト動作を用いたい場合は、この限りではありません。


```vue
<p>画像：<img :src="job.cover" alt=""></p>
```
各求人情報に関連付けられた画像を表示する。

・v-bindでsrc属性をバインドしている＝`:src`

https://ja.vuejs.org/api/built-in-directives#v-bind

### 2.scriptの解説


``` vue
<script lang="ts">
import { ref,reactive} from 'vue'

export default {
  // awaitを使う時は関数の先頭にasyncをつける
  async setup() {
    // ref関数でjobs変数を作成
    const jobs = ref([])
    // await 非同期処理
    // fetch ブラウザのAPIで、HTTPリクエストを発行してデータを取得する
    // APIの中のdataというキーを変数に入れている
    const { data } = await useFetch(`https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs`)
    jobs.value = data._rawValue
    console.log(data._rawValue);
    // const { data: jobs } = await useFetch(`https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs`)
    return {
      jobs,
    }
  }
}
</script>
```

APIからのデータを取得している。

> awaitは、
基本jsは処理の完了を待たずにして下にどんどん実行されていきますが、
awaitとかくとここで処理が終わるまでに待ってもらえます。

ある処理が終わるのを待ってから次の処理を進めたい、、というのを実現してくれる。
例えば、何かをダウンロードする時や今回のようにAPIを取得したい時。（通常のjsだと待たずに次の処理が進んでしまう）

>ちなみにawaitを使う場合はその関数の先頭にasyncをつけないといけないので
setupの前にasyncをつけています。

:::note info
・`await`：非同期処理が終わるまで待つための演算子
・通常、`await`は`async`関数内で使われる。
:::

・Nuxt3の`useFetch()`を使って非同期処理でデータを取得している

https://shibayama-masaki.com/2023/04/01/nuxt3-useasyncdata-usefetch/

↑とてもわかりやすかったです

 `useAsyncData()`は、Nuxt3で非同期処理を実行するための関数

非同期処理を行う場合、
- JavaScript：`axios`を使うことが多い
- Nuxt3：`axios`の代わりに`useAsyncData()`や`useFetch()`を使う

### 3.コードの修正
>実際の開発では、
`const jobs = ref([])`がなくとも、
`const { data: jobs } = await useFetch(https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs)`
という書き方をすれば、jobsのリアクティブ化も行い、それと同時にjobsの中にAPIのデータを入れてくれます。

・<ins>jobs/index.vue<ins>を修正

```vue
<script lang="ts">
import { ref,reactive } from 'vue'

export default {
  async setup() {
    const { data: jobs } = await useFetch(`https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs`)
    return {
      jobs,
    }
  }
}
</script>
```

![スクリーンショット 2023-12-30 14.40.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/c9e35e8f-26f7-5472-c6bf-5d925a32adab.png)


### <ins>jobs/[id].vue</ins>を書き換えて表示を見てみる
```vue
<template>
  <h2>求人詳細</h2>

  <section v-if="job">
    <h3>{{ job.title }}</h3>
    <div>
      <h4>概要</h4>
      <p>{{ job.description }}</p>
      <h4>カバー</h4>
      <p><img :src="job.cover" alt=""></p>
      <h4>作成日</h4>
      <p>{{ job.createdAt }}</p>
    </div>
  </section>
</template>

<script language="ts">

import { ref , reactive } from 'vue'

export default {
  async setup() {
    const route = useRoute();
    const id = route.params.id
    const { data:job } = await useFetch(`https://62fe320941165d66bfbabe7e.mockapi.io/apt/v1/jobs/${id}`)

    return {
      job
    }
  }
}
</script>

<style>
.u-tx-bold {
  font-weight: bold;
}
</style>
```
👇http://localhost:3000/jobs/2
![スクリーンショット 2023-12-30 14.48.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/c1534daa-8062-5827-f92f-d01f9bf8d974.png)

http://localhost:3000/jobs/3
![スクリーンショット 2023-12-30 14.49.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/37277ed2-4545-9072-6fd1-8ecf16204ad1.png)

idの番号によってページが動的に変わりました👏

```vue
    const route = useRoute();
    const id = route.params.id
```

- useRoute();
    - Vue Routerの機能
    - Vue.jsアプリケーション内で現在のページの情報を取得するのに使う

```vue
const route = useRoute();

// 例: /users/123 というURLがある場合
console.log(route.path);        // '/users/123'
console.log(route.params);      // { id: '123' }
console.log(route.query);       // {}

// 例: /users/123?name=John というURLがある場合
console.log(route.query);       // { name: 'John' }
```

今回取得したいのは
http ://localhost:3000/jobs/<ins>**2**</ins>
なので `route.params`を使う。

```vue
 const id = route.params.id
```
この　`[id].vue`のidをconst idに入れて、${id}でAPIのURIの生成に使っている。

### 参考

>key 属性を付与し、要素とデータとを関連付ける（紐づける）

https://note.com/shift_tech/n/nbcae6c4ab442

https://zenn.dev/one_dock/articles/77cd256c887204