Journey

技術に関することと覚書と

Vueでpropsで渡されたものをコンポーネント内でさらにv-modelに渡したい場合

タイトルままですがVueのあるコンポーネントでv-modelで渡されたものを、さらにそのコンポーネント内で別のコンポーネントのv-modelに渡すなどした時に以下のようなwarningが出ます

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.

簡単に言えばv-modelで渡されたものを直接書き換えるなというエラーです。v-modelで渡されたものの変更は $emit でおこなうので当然のメッセージです。 ただタイトルのようなことをしたい場合も多々あっていままでは以下のような手順で行っていました。

<my-component v-model="value" />
// MyComponent.vue
<template>
  <sub-component v-model="subValue" />
</template>

<script>
export default {
  props: {
    value: {
      type: Object,
      required: true
    }
  },
  data() {
    return{
      subValue: this.value
    }
  }
  watch: {
    value() {
      this.subValue = this.value
    }
  }
}
</script>

非常に煩雑でわからづらいですね。ざっと説明すると

  1. propsで渡されたものをdataで適当な変数に代入
  2. そのdataを次のv-modelに入れる
  3. valueの変更に追従できるようにwatchを設定

となっていました。やりたいことはさっと言葉で出ますが、コードは非常に複雑ですね。

解決策

また↑のコードを書こうとしたときにふと思いつき、試してみたコードがこちらです。

<my-component v-model="value" />
// MyComponent.vue
<template>
  <sub-component :value="value" @input="e => { $emit('input', e) }"
</template>

<script>
export default {
  props: {
    value: {
      type: Object,
      required: true
    }
  }
}
</script>

これで期待通りに動きました。sub-component のイベントをそのまま上に流すことによって解決できました。 最初のコードよりもコード量も少なくよさそうなので、今後はこれを使っていこうと思います。