第9回ペパボテックカンファレンス ~ Vue.js 特集 ~ @Joe_nohさんが「Vuex と入力フォーム」にて、「フォームが多くなると辛い(特にmutation)」と話したが、シンプルにフォームデータをcompのローカルstateに詰め込んで、発火するたびにローカルstate丸ごとstoreに投げればいいじゃないかっと思ってちょっとやってみた。
ゴール
- mutationsを減らす
- get, setを減らす
- Vuex wayを守る
- vue-devtoolsを手放さない
GitHub:vuex-form-approach
Demo
ポイント1
compのdataを一つのObjectにしておく(profile)
data () {
return {
profile: {
name: '',
age: 0,
pet: []
}
}
}
ポイント2
全体の発火をしっかりキャッチしてstoreへどん。deep: true
が味噌
watch: {
'profile': {
handler (val) {
this.$store.commit('FORM1_UPDATE_PROFILE', cloneDeep(val))
},
deep: true
}
}
ポイント3
profile.pet[0].name
が変更されても発火しないので子compを作って深い階層のデータ変更を親に伝えよう。(子compを作らないといけない時点で結局辛いよね?)
onChangePet (val, index) {
this.profile.pet[index] = val
this.$store.commit('FORM1_UPDATE_PROFILE', cloneDeep(this.profile))
}
注意
Objectのままstoreに渡す(commit)と「直で変更するな」と怒られるので、immutableなものにしよう。ここではlodashの cloneDeep
で解決。
mutationsはこれだけで済む
[FORM1_UPDATE_PROFILE] (state, data) {
state.profile = data
}
最後に
実務では...そう簡単にはいかないので action
に投げて加工してからcommitするんじゃないかな?
これで目的は達成したが、データ丸ごとstoreにってのはお行儀よくないし、入力した値がお互い影響し合うような複雑な業務システムだとバグ出やすいので、面倒だが丁寧に get
set
を書きたい。
他にいい方法があればぜひ教えてください!