mmyoji's diary

プログラミングとか日々のどうでもいいこととか

Vue.jsのデータバインディングのつらみ

起きた問題

原因

  • propsで渡したデータを使って、子のtemplate内で何かしら表示を変更する、ということが書かれていない限り、propsの変更をwatchして、子を描画し直してくれない
  • 明示的に $watch する必要性
  • 当たり前っちゃ当たり前

具体例

うまく動かないケース

index.html

<!-- body より内側 -->
<div id="app">
  <h2 v-on="click: changeMsg">FOOOOO</h2>
  <hoge-component msg="{{msg}}"></hoge-component>
</div>

app.js

// vueify使ってます
import HogeComponent from "./HogeComponent.vue"

let app = new Vue({
  el: "#app",
  data: {
    msg: "foofoo"
  },
  components: {
    HogeComponent: HogeComponent
  },
  methods: {
    changeMsg() {
      this.msg = "uwaaaaa"
    }
  }
})

HogeComponent.vue

<template>
  <p class="foobar">foobar</p>
</template>

<script lang="es6">
  import $ from "jquery"

  export default {
    props: ["msg"],
    ready() {
      // (あえてやってます)jQueryでpタグの中身を更新
      let $elem = $(".foobar")[0]
      $elem.text(this.msg)
    }
  }
</script>

この程度の処理ならいいんですが、d3にデータを渡して云々とかってなると、別のクラスに処理を移譲してそいつが描画等を担当することになるのでその時は以下のようにしましょう。

上手く動く例

HogeComponent.vue

<template>
  <p class="foobar">foobar</p>
</template>

<script lang="es6">
  import $ from "jquery"

  export default {
    props: ["msg"],
    ready() {
      this.$watch("msg", (newVal, oldVal) => {
        let $elem = $(".foobar")[0]
        $elem.text(newVal)
      })
    }
  }
</script>

やったね