Vue公式チュートリアル 〜 変数の変化をチェックする

記事
IT・テクノロジー


Vue 公式チュートリアル 〜 変数の変化をチェックする
Vue 公式チュートリアルのステップ 10 は、変数の状態が変わるのをチェックする方法です。Javascript の変数を表示に使う場合、変数が変わったら表示も更新したい場合が多くなります。そういう場合のやり方です。


前回までのポイントは?

Vue の公式チュートリアルもステップ 10 まで来ました。 何となく Vue で、Web ブラウザに表示させるやり方がわかってきたのではないかと思います。 ステップ9までで、基本的な Vue の部品の書き方がわかって、HTML と Javascript、HTML と CSS、CSS と Javascript の連携のやり方も一部は体験しているので、あとは「回数」を増やして実際に使えるようになる様な練習が必要になってきます。

今回のポイントは?
ステップ10では、新しいポイントがいくつかあります。

まずは、変更前のサンプルコードを見てみましょう!

<script>
export default {
  data() {
    return {
      todoId: 1,
      todoData: null,
    };
  },
  methods: {
    async fetchData() {
      this.todoData = null;
      const res = await fetch(
        `h t t p s://jsonplaceholder.typicode.com/todos/${this.todoId}`
      );
      this.todoData = await res.json();
    },
  },
  mounted() {
    this.fetchData();
  },
};
</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId++">Fetch next todo</button>
  <p v-if="!todoData">Loading...</p>
  <pre v-else>{{ todoData }}</pre>
</template>
HTML の部分(「template」のタグの部分)からみてみると、以前出てきたのと似た記述があります。

<p>Todo id: {{ todoId }}</p>
<button @click="todoId++">Fetch next todo</button>
この部分は、「Fetch next todo」のボタンを押すと、変数「todId」が1づつ増えていくような記述になっています。その「todoId」をボタンの上に表示しています。

実際に、この状態のコードでボタンを押すと表示される数が増えていくのがわかります。

その下の部分は、これも以前のステップで学習した「v-if/v-else」で「todoData」の状態によって、表示を変えるようにしています。

<p v-if="!todoData">Loading...</p>
<pre v-else>{{ todoData }}</pre>
です。「!todoData」にデータがなければ、「Loding...」を表示して、データがある場合は、「todoData」を表示するようになっています。

Javascript では、以下のようになっています。

<script>
export default {
  data() {
    return {
      todoId: 1,
      todoData: null
    }
  },
  methods: {
    async fetchData() {
      this.todoData = null
      const res = await fetch(
        ` h t t p s://jsonplaceholder.typicode.com/todos/${this.todoId}`
      )
      this.todoData = await res.json()
    }
  },
  mounted() {
    this.fetchData()
  }
}
</script>
まずデータの最初の値は、「todoId」が「1」、「todoData」は「null」が入っています。 「null」は「データがない」という状態を表しています。従って、この状態では、HTML の部分の表示は「データがない」状態になるので、「Loading...」が表示される事になります。

しかし、前回のステップで学習したように、この Javascript には「mounted(){}」の処理が書かれているので、この Vue の部品が表示できる状態になった時点で、メソッド(関数)「fetched()」が呼び出されます。 このメソッド関数をみると、インターネット上の URL からデータを取ってくるという処理が書かれています。

「fetch()」という関数は、指定された URL のデータをインターネットから取ってくる、Javascript で標準でサポートされている機能になります。

ここで、また新しい書き方が出てきています。

* fetchData()の処理の記述の前に「async」がついています
* fetch()を呼び出しているところの前に「await」がついています
実は、これが「非同期」の処理を表しています。慣れない言葉が出てきましたが、インターネットからデータを取ってくると言う処理は、PC 上で動く普通の処理と違って二つの大きな違いがあります。

* インターネット上の別のコンピュータからデータを取ってくるので「時間がかかる」
* 別のコンピュータからのデータなので「いつデータが届くかわからない」
なので、通常の処理(非同期処理に対して同期処理といいます)は、上から順番にプログラムに書いた順序で処理されますが、非同期の処理の場合は、結果を待たずに、待っている時間が勿体無いので別の処理を始めてしまいます。

そこで、プログラムを書くときに、「この処理は非同期」というラベルをつけて、順番に処理するか、別の処理を先にやるかをわかるようにしています。そのラベルが「async」つまり、非同期(asynchronous)を示しています。

ここで呼び出している「fetch()」の処理も実際の処理が書かれているところでは、非同期のラベルが付けられている関数になっています。

ところが、このプログラムでは、「fetch()」の処理結果、つまりネットワークでとってきたデータを「this.todoData」に入れているので、この処理を先にする事ができません。そこで、「await」を付けて、結果がくるまで待ってから次の処理をするという指示を書いています。結果的に上から下に順番で実行されるので、見かけ上は同期の処理と同じになっています。

このインターネットで取得したデータが「todoData」に入るので、実際の表示は、

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}
が表示されます。

HTML の部分では「pre」という新しいタグが使われていますが、これは予め CSS などで表示の仕方を決めた方法で表示されるというタグです。今回は、CSS 部分の記述が書かれていないので、標準の状態の表示になっています。

と言うのが変更前のコードです。 この変更前のコードには問題があって、「userId」は、ボタンを押す度に1づつ増えていくのですが、「fetchData()」の処理が呼び出されるのは、この「部品」が表示できる状態になった時だけなので、表示されている「todoData」は更新されません。

この課題では、「todoId」が更新されたら、新しいデータをインターネットから取得して、表示も更新できるようにすると言うのが課題です。

変更後のコードは?

以下が変更後のコードです。

<script>
export default {
  data() {
    return {
      todoId: 1,
      todoData: null,
    };
  },
  methods: {
    async fetchData() {
      this.todoData = null;
      const res = await fetch(
        `h t t p s://jsonplaceholder.typicode.com/todos/${this.todoId}`
      );
      this.todoData = await res.json();
    },
  },
  mounted() {
    this.fetchData();
  },
  watch: {
    todoId() {
      this.fetchData();
    },
  },
};
</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId++">Fetch next todo</button>
  <p v-if="!todoData">Loading...</p>
  <pre v-else>{{ todoData }}</pre>
</template>
違いは、Javascript の「watch:{}」が付け加えられている点です。

watch: {
    todoId() {
      this.fetchData()
    }
}
これが、変数「todoId」が変更された場合の処理を決めている部分です。「watch:{}」の中に、変数名と同じメソッドを書いて、その中で必要な処理を書きます。この例では、「this.fetchData()」を呼び出しています。 この記述を追加すると、表示されている「todoData」の内容も更新されてボタンをクリックする度に表示が更新されます。

「todoData」の方は、「todoId」が更新されると、「fetchData()」が呼び出されて、「todoData」が更新されるので、Vue が自動的に表示を更新指定くれます。これは、「todoId」を表示している部分と同じ仕組みです。

問題は、「todoId」が更新された際に、「fetchData()」が呼び出されないために、「todoData」が更新されなかったので、「fetchData()」が呼び出せるようになれば、問題は解決すると言う事です。

今回の応用編は?

「pre」の仕組みが今ひとつよくわからないと思いますので、CSS に「pre」の記述を書いてどうなるかを体験してみる事にします。

<style>
    pre {
        color: red;
        font-weight: bold;
    }
</style>
を変更後のコードに追加してみてください。 表示されるデータが「赤」になって、フォントが太字に変わると思います。

まとめ
ステップ10では、Javascript の変数の値の変化を監視して、データが更新された際に特定の処理をしたい場合には、「watch:{}」で監視する変数を指定すると、変数の値が変わった時に必要な処理を行う事ができます。

この部分は、比較的シンプルですが、このステップで出てきた「非同期」の処理は、Javascript ではわかりにくい処理の一つです。今回は、「await」を付けてデータの処理の完了を待って次の処理を行なっているので、見かけ上は普通の処理と変わらないので余り混乱はないと思います。

しかし、「await」を付けないで「非同期」の関数を呼び出すと、非同期の処理の完了を待たずに次の処理が実行されるので、見かけ上は、「変な順番」で処理が行われているようになるため、今回のように、非同期の処理結果を後の処理で使う場合などは、予期しない動作になってしまいます。

非同期の処理は、Javascript では幾つか違った書き方ができる様になっているので、将来はもう少し詳しく学習する必要があります。このステップでは、「非同期」の処理が Javascript にはあって、処理の順番が上から順番に行われない場合もあると言うことを覚えておいてください。

次回は、2022 年 3 月 7 日にお届けします。お楽しみに!
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す