0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

わかったようでわからない非同期処理の完全理解③:Axiosで複数のソードを一覧表示してみる

0
Posted at

前回はAxiosを使い、ソード情報を受け取れたときは .then()、受け取れなかったときは .catch() を使う流れを見てみました。

今回は、複数のソードを受け取り、Vue 3の v-for で一覧表示してみます。.then()async / await のどちらを使うのかも、自分なりに整理してみました。

まだ途中段階なので、勘違いなどあれば教えていただけるとうれしいです。

今日やったこと

Axiosで受け取った複数のソードを、数に合わせて画面へ並べてみました。

前回は、1本のソード情報を受け取りました。

{
  "name": "Iron Sword"
}

今回は、ソードを3本受け取ることにします。

[
  {
    "id": 1,
    "name": "Iron Sword"
  },
  {
    "id": 2,
    "name": "Wood Sword"
  },
  {
    "id": 3,
    "name": "Silver Sword"
  }
]

このJSONファイルは、public/swords.json に置く想定です。

ゲームで考えると、鍛冶屋から1本だけ受け取るのではなく、持ち物袋を開いて、今持っているソードを一覧で見る場面に近そうです。

キャラクター 「ソードが3本あるなら、画面にも3枚並んでほしいね。持ち物袋を開く感じになりそう」

まずは、Axiosでソード一覧を読み込みます。

<script setup>
// Axiosを使えるように読み込む
import axios from 'axios'

// onMountedは画面が表示された後に処理を始めるために使う
// refは画面に表示する値を覚えておくために使う
import { onMounted, ref } from 'vue'

// 受け取ったソード一覧を入れる箱
// 最初はソードが0本なので、空の配列を入れる
const swords = ref([])

// 読み込み中かどうかを覚えておく
const isLoading = ref(true)

// 読み込みに失敗したときの文章を入れる
const errorMessage = ref('')

// ソード一覧を読み込む関数
const loadSwords = async () => {
  try {
    // swords.jsonを取りに行き、データが届くまで待つ
    const response = await axios.get('/swords.json')

    // Axiosで受け取ったソード一覧はresponse.dataに入っている
    swords.value = response.data
  } catch {
    // データを受け取れなかったとき、画面に出す文章を入れる
    errorMessage.value = 'ソード一覧を受け取れませんでした'
  } finally {
    // 成功でも失敗でも、読み込み中は終わりにする
    isLoading.value = false
  }
}

// 画面が表示された後に、ソード一覧の読み込みを始める
onMounted(loadSwords)
</script>

<template>
  <main>
    <!-- データを待っている間だけ表示する -->
    <p v-if="isLoading">持ち物袋を確認しています...</p>

    <!-- データを受け取れなかったときに表示する -->
    <p v-else-if="errorMessage">{{ errorMessage }}</p>

    <!-- データを受け取れた後に表示する -->
    <section v-else>
      <h1>ソード一覧</h1>

      <!-- swordsの中にあるソードの数だけarticleを繰り返す -->
      <article v-for="sword in swords" :key="sword.id">
        <!-- 今表示している1本のソード名を表示する -->
        <p>{{ sword.name }}</p>
      </article>
    </section>
  </main>
</template>

画面では、次の順番で変わります。

  1. 最初は「持ち物袋を確認しています...」と表示される
  2. Axiosが swords.json を取りに行く
  3. ソード一覧が届く
  4. swords の箱に3本のソード情報が入る
  5. v-for がソードの数だけ表示を作る
  6. 画面に3本のソード名が並ぶ

つまずいたところ

.then()async / await を両方使う必要があるのか、最初は分かりませんでした。

2つとも書く必要はない

AxiosはPromiseを返します。 axios

Promiseを受け取る書き方には、主に2つあります。

  • .then() / .catch() を使う
  • async / awaittry / catch を使う

同じAxios通信で、2つとも書く必要は基本的にありません

前回は、成功と失敗の分かれ道を見やすくするために、.then() / .catch() を使いました。

// ソード一覧を取りに行く
axios.get('/swords.json')
  .then((response) => {
    // 受け取れた後に、ソード一覧を使う
    swords.value = response.data
  })
  .catch(() => {
    // 受け取れなかった後に、失敗の文章を入れる
    errorMessage.value = 'ソード一覧を受け取れませんでした'
  })

今回は、読み込み中・成功・失敗まで順番に見たかったため、async / await を使っています。

const loadSwords = async () => {
  try {
    // ソード一覧が届くまで待つ
    const response = await axios.get('/swords.json')

    // 受け取れた後に、ソード一覧を使う
    swords.value = response.data
  } catch {
    // 受け取れなかったときに、失敗の文章を入れる
    errorMessage.value = 'ソード一覧を受け取れませんでした'
  }
}
キャラクター 「ソードを受け取る方法が2つあるだけで、受け取れるソードが増えるわけではないんだね」

今の自分には、次のように見えています。

書き方 成功したとき 失敗したとき 読み方
.then() / .catch() .then() の中 .catch() の中 成功ならこっち、失敗ならこっち
async / await await の次の行 catch の中 待つ、受け取る、次へ進む

どちらも「データが届いてから使う」「失敗したら画面へ知らせる」ことができます。

今回、async / await を使った理由

今回の画面には、3つの状態があります。

  • データを待っている
  • ソード一覧を受け取れた
  • ソード一覧を受け取れなかった

そのため、上から順に追える async / await の形を試してみました。

const loadSwords = async () => {
  try {
    // 1. データを取りに行く
    const response = await axios.get('/swords.json')

    // 2. 受け取れたら、一覧を画面用の箱へ入れる
    swords.value = response.data
  } catch {
    // 3. 受け取れなかったら、失敗の文章を入れる
    errorMessage.value = 'ソード一覧を受け取れませんでした'
  } finally {
    // 4. 成功でも失敗でも、読み込み中を終わりにする
    isLoading.value = false
  }
}

ゲームの例では、「持ち物袋を確認する → ソードがあれば並べる → 見つからなければ知らせる → 確認中の表示を終える」と順番に進めるような形です。

今の理解(メモ)

ソード一覧を表示するために、今回出てきたものを整理します。

  • ref([]):複数のソードを入れる空の持ち物袋
  • axios.get():ソード一覧を取りに行く
  • await:ソード一覧が届くまで待つ
  • response.data:Axiosが受け取ったソード一覧
  • swords.value:画面に出すソード一覧を入れる場所
  • v-for:ソードの本数に合わせて表示を繰り返す
  • try:うまくいくか試す場所
  • catch:失敗したときにすることを書く場所
  • finally:成功でも失敗でも最後にすることを書く場所

v-for は、配列に入っているデータの数だけ、同じ形の表示を繰り返すために使えます。 ja.vuejs

<!-- swordsの中から、1本ずつswordとして取り出す -->
<article v-for="sword in swords" :key="sword.id">
  <!-- 取り出したソード名を表示する -->
  <p>{{ sword.name }}</p>
</article>

今回の swords.json にはソードが3本あるため、article も3回作られます。

Iron Sword
Wood Sword
Silver Sword
キャラクター 「空の持ち物袋にソード一覧が入ったら、`v-for` が本数ぶん表示してくれるんだね」

ref の値が変わると、Vueは画面の表示も更新します。Vue.js公式ドキュメント また、onMounted() は画面が表示された後に処理を始めるために使えます。 ja.vuejs

次にやりたいこと

ソード一覧を表示できたので、次は一覧を操作できる画面にしてみたいです。

  • ソードに画像と説明を追加する
    名前だけでなく、アイテムカードらしい見た目にしてみたいです
  • ソードが0本の場合の画面を作る
    持ち物袋が空のときに、何を表示するか考えたいです
  • 各ソードに「装備する」ボタンを付ける
    選んだソードを、今の装備として画面へ表示してみたいです
  • ボタンを押したときに一覧を読み込み直す
    利用者の操作で、一覧が変わる流れを試したいです
  • .then() / .catch() の形でも同じ一覧を作る
    自分にはどちらの書き方が読みやすいか、見比べたいです

今日の整理

今回は、Axiosで複数データを受け取り、Vue 3で一覧表示する流れを整理しました。

順番 すること 今回の例
1 空の配列を用意する const swords = ref([])
2 Axiosでデータを取りに行く axios.get('/swords.json')
3 データが届くまで待つ await axios.get(...)
4 受け取った一覧を箱へ入れる swords.value = response.data
5 v-for で数だけ表示する v-for="sword in swords"

.then() / .catch()async / await は、どちらもAxiosの結果を受け取るための書き方です。

今回の整理 .then() / .catch() async / await
使う場面 成功と失敗を分けて見たいとき 処理を上から順に追いたいとき
成功した後 .then() の中 await の次の行
失敗した後 .catch() の中 catch の中
両方が必要か 基本的にはどちらかを選ぶ 基本的にはどちらかを選ぶ

おわりに

今回は、Axiosで受け取った複数のソード情報を、Vue 3の v-for で一覧表示してみました。

.then() / .catch()async / await は、同じ通信処理で両方使う必要はないと分かりました。前回は成功と失敗を見分けやすい .then() / .catch() を使い、今回は処理の順番を追いやすい async / await を試してみました。

次は、一覧のソードをボタンで選び、「今装備しているソード」を画面へ表示するところまで進めてみたいです。画像解析結果や検索結果も、同じように一覧で扱えるようになりたいです。

学習中の内容なので、勘違いや理解不足もあると思います。もし気になる点があれば教えてもらえるとうれしいです。

 注意事項
 本ブログに掲載している内容は、私個人の見解であり、
 所属する組織の立場や戦略、意見を代表するものではありません。
 あくまでエンジニアとしての経験や考えを発信していますのでご了承ください。

0
0
0

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?