created: 2019-10-30 00:00:00,tags:javascript,vue,spa,

Vue.js のコンポーネントを作る話

Vue.js でコンポーネントを作っている時に入力フォーム単位でコンポーネント化する事自体はよくやるけど、 そのコンポーネントをある程度の塊にした時に $emit で上手く扱う方法が欲しかった。

試してみる

やりたい事は下記 2 点。

  1. 子のコンポーネントには親から貰った Object を分解して渡す
  2. 親には、それぞれの子の変更を親から貰った Object に反映して戻す

上記をやるには Vue の算出プロパティで getter, setter を定義する事で実現できる。

上記を実現してみるとサンプルコードは下記のようになる。

<template>
<div>
  <huga-component
    :inputField=.sync"hoge">
  </huga-component>
  <huga-component
    :inputField=.sync"huga">
  </huga-component>
</div>
</template>

<script>
export default {
  name: "HogeComponent",
  props: {
    form: {
      default: function () {
        return {}
      },
      type: Object
    }
  },
  computed: {
    hoge: {
      get() {
        return this.form.hoge
      },
      set(value) {
        this.form.hoge = value
        this.$emit('update:form', this.form)
      }
    },
    huga: {
      get() {
        return this.form.huga
      },
      set(value) {
        this.form.huga = value
        this.$emit('update:form', this.form)
      }
    }
  }
}
</script>

親側は下記。

<template>
  <hoge-component
    :form.sync="form.hogeComponent">
  </hoge-component>
</template>

<script>
import HogeComponent from 'HogeComponent'
export default {
  name: 'ParentComponent',
  components: { HogeComponent },
  data() {
    return {
      form: {}
    }
  }
}
</script>

親では data で定義した form Object の中にそれぞれのコンポーネントから上がってくる Object を保持する狙い。 コンポーネント単位でまとめて上げる場合、その構造をそのまま持ちたい欲求があるのでそういう場合に使える。

vuex で store を使って持ち回した方がいい場合は多いと思うけど、この形式の場合コンポーネント毎で上がってくるデータが簡単に取れるので、部品の使い回しという観点では内部を知らなくても使える為楽ではあるかなと。

感想

まだ SPA を書く経験が圧倒的に足りていないのでなんとも言えないけど、form 周りは store を使うのはなかなか面倒そうな印象。 store を使えば emit が不要かと言えばそうでもなく、まぁ適切に使うという話にしかならないのかなと感じた。