Aikの技術日記

技術的な進捗とか成果とかを細々と投稿するブログです。時々雑記も。

Nuxt.js使ってみた Part4~小ネタ:computedとmethodsの違い編~

はじめに

お久しぶり?です、筆者です。

前回は、Part2で実施したチュートリアル実践中に気になり深掘りしたこと3つ:

  • Vuexとは?
  • computedとmethodsの違い
  • propsとdataの違い

…のうち1番目の「Vuexとは?」についてまとめてみました。

今回では、2番目となる「computedとmethodsの違い」についてを見ていこうかなと。
※結構ボリューム多くまとめちゃったので、ご了承をば…。

それでは行きましょう。

computedとmethodsの違い

公式記事によると、computedは正式には「算出メソッド」、methodsはそのまんま「メソッド」という意だそうで。
jp.vuejs.org

computedとmethodsの違いは、「リアクティブな依存関係にもとづきキャッシュしてくれる」こと。
※リアクティブという単語の意味については、こちらの記事が分かりやすかったです:
リアクティブプログラミングへの理解がイマイチだったのでまとめてみた - UUUM攻殻機動隊(エンジニアブログ)

公式記事の例をまんま持ってきますが…例えば下記の様なコードがあった際:

<p>Reversed message: "{{ reverseMessage() }}"</p>
// コンポーネント内
computed: {
  reverseMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

上記の様にcomputedでreverseMessage()を定義すると、this.messageの値が変化した時にしかreverseMessage()メソッドは再実行されません
つまり、this.messageの値が変化しない限り「再度メソッド実行することなく以前計算された結果を即時に返してくれる」のです。

ただし、下記の様にmethodsで定義してしまうと:

methods: {
  reverseMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

this.messageの値が変化しようがしまいが、reverseMessage()レンダリング時に常に再実行されます。

じゃあmethodsってどういう時に使うのかというと、下記の様な「算出結果をキャッシュして欲しくない処理」に使用するとよいようです。
例えば、下記の様なDate.now()を使用する処理を算出プロパティで書いてしまうと…

computed: {
  now: function () {
    return Date.now()
  }
}

Date.now()の変更はVue.jsでは検知できないため、このメソッドは「実行されてから永遠に返却値が変わらないメソッド」となってしまいます。コマッタ!
こういう関数を使いたいときは、methodsを使えということでしょうね。

補足: watchについて

「値の変更を検知し」「検知されたら実行する」処理をしたい時に…。
Vue.jsでは「監視プロパティ(watch)」というものが提供されています。

ただ、公式Wikiには「大概の場合はcomputedを使う方がいい」とありました。
その理由は下記のコードを見比べればわかるかと:

<div id="demo">{{ fullName }}</div>
// watch使用Ver
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})
computed使用Ver
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

上記の例だとfullNamefirstNamelastNameに依存するため、computedでひとまとめに処理した方が良かったですが…。
1つの値によって、アプリケーションの状態が繊細に変化する様な状況ではwatchの方が良さそうですね。

補足: computedを深掘りしてみる

公式記事を元に、computedが具体的にどんな振る舞いをするのかもみてみました。
jp.vuejs.org

というか公式記事、チュートリアルだけでなく内容の深いところまでしっかり書いてくれているからすごく参考になりますね…。
若干説明が分かりにくいので、こうして別途記事にまとめた方が理解しやすいですが。

閑話休題
例えばこんな感じのコードがあるとします:

<div id="example">
  <p>元々のメッセージ: "{{ message }}"</p>
  <p>反転したメッセージ: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    // 算出 getter 関数
    reversedMessage: function () {
      // `this` は vm インスタンスを指します
      return this.message.split('').reverse().join('')
    }
  }
})

こういう風に書くことで、reversedMessageは「プロパティvm.reversedMessageに対するgetter関数」として宣言されます。
そしてさらに、この値はvm.messageに常に依存するようになっており。

これにより、Vue.js側がmessagereversedMessageの依存関係を知ることができるため…。
messageが変更されたらmessageに依存している他の処理(ここでいうとreversedMessageですね)も再実行される」様にできるのです!

computedはこの様にして、依存している値と連動できてるんですなぁ。

おわりに

今回はチュートリアルで作成したコードのカスタマイズの中で気になった項目3つ:

  • Vuexとは?
  • computedとmethodsの違い
  • propsとdataの違い

…の内、「computedとmethodsの違い」について見ていきました。
computedとmethodsの他にも、watchについてもまとめちゃうことになりましたね…。

これら3項目について、本記事では「各項目が何を示すのか」に着目してまとめていきましたが…。
純粋に各項目の比較をしたいなら、こちらの記事が分かりやすくておすすめです。
qiita.com

次回記事では、最後となる「propsとdataの違い」について見て行ければと。

それでは|д゚*)