v-model を捨てる選択肢
v-model
Vue.js で便利な機能の一つに v-model
があります。
v-model
にデータを渡すと自分でフォームのイベントを利用し値を更新するということをしないで済む。
確かに便利ですが、コンポーネントがネストされていくにつれ親コンポーネントで v-model
を利用するために
<template> <input type="text" :value="value" @input="handleInput" /> </template> <script> import Vue from "vue"; export default Vue.extends({ props: { value: { type: String } }, methods: { // これより上の階層のコンポーネントの場合は // handleInput(value) { // this.$emit("input", value) // } handleInput(event) { this.$emit("input", event.currentTarget.value); } } }); </script>
というのを実際に v-model
を使用するコンポーネントまで続けることになってしまいます。
1 つ上の階層の場合 emit
で親コンポーネントにわたす値が変化します。一定以上の Vue.js の経験がある。もしくはしっかりとコンポーネントの管理がされていない場合には間違った値を渡す可能性も考えられます。(v-model
が 糖衣構文であることを知らない人も結構いる気がします。)
Props で管理する
emit
を使用するのではなく親から関数を props
で受け取り、それを子コンポーネントでは発火させることで、 emit
時のような親コンポーネントへ渡す値を考慮する必要がなくなります。
ただし、 v-model
で利用できる修飾子(.number
, .lazy
など)が利用できなくなるデメリットが存在します。
実際の子コンポーネントは以下の感じになるかと思います。
template> <input type="text" :value="value" @input="input" /> </template> <script> import Vue from "vue"; export default Vue.extends({ props: { value: { type: String }, input: { type: Function } } }); </script>
このパターンでは props
を利用していることから特に props
の命名に縛られないため柔軟に利用できるということです。
例えば input 要素を 2 つ持つようなコンポーネントを考えると v-model
を利用するためには props
として value がいなければならず、 emit もそれぞれの input 要素から取得した値をなんとかまとめて親に値を渡すなどということになります。
しかし、 props
のみで管理すればそれぞれの input 要素を利用する状況に応じた命名をしそれぞれ関数を渡すだけで良くなります。 子コンポーネントから渡ってくる値の形式に気を配らなくてよくなるのです。
まとめ
props
で関数を渡すパターンの方が大抵の場合柔軟に利用できるのではないかと思います。
もちろんシンプルなコンポーネントのみで済むのであれば、数々の修飾子を利用できる v-model
が利用可能になるパターンを使って恩恵を受けるのがいいでしょう。
変に v-model
にこだわらずに捨てる選択肢を持つことで柔軟にコンポーネントを開発していきましょう。
サンプルとして簡単なものですがリポジトリを置いておきます。