対象とする読者
Vueのwatchが色々試したけど効かなくて困っているひと
まえおき
もうVueを使うようになって7年は経つだろうか。
自分で言うのもなんだが、もうだいぶ慣れている。
コードが美しいだとか、仕様に対する造形が深いとかそういう観点では未熟者ではあるけれど
Vueは僕にとって日曜大工する時の工具みたいなもので、「こういうWeb画面を作りたいなー」と思った時にだいたい実現出来る素晴らしいツールだ。
とはいえ使い方の分からない機能も多く、プラスドライバーがあるのにマイナスドライバーを使うなんて事もしょっちゅうである。
しかし、いざ道具をちゃんと使おうとすると、見つからなかったり、うまく使えないなんてトラブルにでくわす。
僕にとって Vue の watch というのは、そこそこ頻繁に使うわりに上手く使えなくなる時がある道具の一つなのだ。
長年使っていることもあって watch を使用するうえで注意しなければならない事はある程度心得ているつもりだったが、久々にしっかり悩まされたので共有したい。
watchの心得
僕が普段から watch を使う時に気をつけているのはこのあたりだ。
- 対象のプロパティは最初から定義しておく。
- pushとか$setとかそういうのを使う。
- deepを使う。
- deepを使うときは handler を使う。
すぐ見つかる情報なので本記事では詳細は省くことにする。
(こういった情報を紹介してくれている人には感謝してもしきれない。何度も救われたし、これからもお世話になる。)
いよいよ本題
僕はいつものようにwatchを実装したものの、うんともすんとも言わなくて困った。
そのときのコードっぽいものを書いてみたので眺めてみて欲しい。
問い合わせフォームをイメージして書いたコード
// << 省略 >>
export default {
name: 'toiawase_form',
components: {},
data () {
return {
dataLoading: true,
faq_list: [],
input_form: {
category: 1, // 問い合わせ種別
message: "", // 問い合わせ内容
placeholder: "", // 入力例
},
}
},
props: {
customerId: Number,
},
mounted () {
this.init()
},
watch: {
'input_form.category': {
handler: function (newVal) {
// 種別が変更されたら入力例を変えてあげようかな
console.log(newVal) // いったんログを出すか。。。しかし、ここが実行されない、、
},
deep: true,
},
},
filters: {
numberFormat (num) {
// よくコピペして用意するやつ。数字に3桁ごとにカンマを付ける。本記事の主旨とは直接関係ない。
if (num) {
return num.toString().replace(/(\d)(?=(\d{3})+$)/g , '$1,')
}
return num
},
},
computed: {
filteredFaqList () {
// 読み込んだFAQの中から問い合わせ種別に関係あるものだけ表示しよう
let list = []
for (let row of this.faq_list) {
if (row.category == this.input_form.category) {
list.push(row)
}
}
return list
},
},
watch: {
customerId (newVal, oldVal) {
this.loadCustomerData()
},
},
methods: {
init () {
// FAQデータを読込む
this.loadFaqList()
},
// << 省略 >>
コメントに書いてある通り、問い合わせ種別に変更が発生してもログが出なかった。
問い合わせ種別というのは セレクトボックスで指定できるイメージだ。
v-modelでプロパティと紐づいていると思ってほしい。
すこし無理やりだが、下記のように値を変更してもダメだった。
this.$set(this.input_form, 'category', '2')
なぜダメなのかお分かりだろうか。
エラーは出てなくてwatch以外はしっかり動作していた。
すぐに分かった人はすごい。
同様の経験をしたことがある人かもしれない。一緒に酒を飲みたい。
僕はあの手この手で値を変更してみたり、watchについて調べ直したり
functionの書き方を変えてみたり、ただの文字列型にしてみたり、ブラウザのキャッシュを消してリロードしているかとか、スペルミスが無いかとか、関係ないコードを更新していないかとか、ブラウザを変えてみたり、馴染むのに時間がかかるのかなとか呟いてみたり。
ざっと半日は費やしてしまった。
で、ようやく気づいたのが 末尾付近。 methodsの手前
watchを2回書いてしまっている。。。
エラーとか出ないから注意して欲しい。
少しだけ言い訳させてほしい。実際のコードはもっと色々と書いてあって、だいーーーぶ離れていたのだ。
僕は半日を棒に振ってしまった。。
しかし今日は金曜日。こういった不具合を来週に持ち越さなかったのはエンジニアにとって素晴らしいことだと思う。
この記事を読んでくれた方々にも、いつもより良い週末が訪れますように。