propsの変更が反映されない

`props`を直接`v-model`に指定したらハマったのでメモ

## 環境
- vue 2.6.11
- JavaScript

## 何がしたかったか
子コンポーネントのクリックイベントで、選択された値を親コンポーネント経由で
別の子コンポーネントに渡したかった。

図にすると以下のような形。

![データの流れ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/946622/109265c4-8aaa-572b-5f3b-f98e90e2d762.png)

もっと詳細に説明すると、カレンダーアプリを作っていて、以下のような構成にしていた。

| コンポーネント名 | 概要 |
| -- | -- |
| componentA | 予定登録用のモーダルダイアログ |
| componentB | カレンダーの実体を持つコンポーネント(月表示用ビュー)<br /> componentCに直接記述していないのは、タブで月・週・日表示を<br />切り替えたかったため |
| componentC | カレンダーページ |

componentAで選んだ日付をcomponentC経由でcomponentBの初期値に設定したかった。

***ここで問題になったのは、componentC -> componentBへのデータの渡し方***

## ダメな例
※`componentA`のソースは省略しています。
### propsをdataの初期値に指定
```
var componentB = {
    props: {
        'initDateString': String
    },
    data() {
        return {
            // ① propsで受け取った値をdataに代入
            startDate: this.initDateString
        }
    },
    template: `
        <div>
            <input type="date" v-model="startDate">
        </div>
    `
}

var componentC = {
    components: {
        componentA,
        componentB
    },
    data() {
        return {
            selectedDate: null
        }
    },
    methods: {
        selected(value) {
            this.selectedDate = value
        }
    },
    template: `
        <div>
            <component-a @click="selected"></component-a>
            <component-b :init-date-string="selectedDate"></component-b>
        </div>
    `
}
```
これがうまく行かなかったのは、以下が原因。

***ソース中①***
`data`に`props`を代入しても、dataとpropsが関連付けられるわけではないため、
２回目以降のpropsの変更は、dataには反映されない

componentC -> Bに渡している値の初期値が`null`なので、
componentBの初期値としては何も設定されていない状態から変更されることがない。

### propsをcomputed経由でdataの初期値に指定
componentCは変更なしのため省略

```
var componentB = {
    props: {
        'initDateString': String
    },
    data() {
        return {
            // ① computed経由で初期値を設定
            startDate: this.dateString
        }
    },
    template: `
        <div>
            <input type="date" v-model="startDate">
        </div>
    `,
    computed: {
        dateString() {
            return this.initDateString
        }
    }
}
```
これがうまく行かなかったのは以下が原因

***ソース中①***
そもそも`data`への初期値代入の処理が通るのはインスタンス生成時の１回のみ
なので`computed`から返される値には`props`の変更が反映されるが、
そのcomputedを呼び出す処理が最初しか通らないので、先程と同様の状態。

## 解決方法
### computedにgetter,setterを用意し、v-modelに設定する
componentCは変更なしのため省略

```
var componentB = {
    props: {
        'initDateString': String
    },
    data() {
        return {
            // ① dataでは初期値設定しない
            startDate: null
        }
    },
    template: `
        <div>
            <!-- ② computedをバインドする -->
            <input type="date" v-model="bindStartDate">
        </div>
    `,
    computed: {
        bindStartDate: {
            get() {
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　// ③ 初期表示にのみ利用
                // setterで別プロパティを指定しているので、その後DOMの値と連動しない
                // ここはちょっと特殊なことしているかも
                return this.initDateString
            },
            set(value) {
                // ④ 実際に保存に利用するプロパティにセットする
                // そもそもpropsを子コンポーネントで書き換えるとエラーになる
                // もし書き換えたければ、this.$emit('change', value)で
                // 親コンポーネントで書き換えて再度propsで渡し直す
                this.startDate = value
            }
        }
    }
}
```

↑は`watch`使ってもできるみたい。
省略しているが、実際のソースの`data`にはもう１つ`endDate`があって、
全く同じこと(setterでセットするのが`endDate`なだけ)しているので、
この場合はwatch使ったほうがシンプルだったかも？

というか、このつくり自体あまり良くないのかな、、、？ ちょっと複雑になってしまったし。

↓参考にさせていただきました。
https://ics.media/entry/200716/
https://qiita.com/simezi9/items/c27d69f17d2d08722b3a