【Vue】リアクティブ変数初期化順序によるwatchEffectの挙動変化
はじめに
watchEffectに記述した内容が意図しない挙動をしていたので調べた備忘録です。
watchEffectとリアクティブな変数の初期化順序について
watchEffectはリアクティブな変数の変更を監視し、変更があった場合にコールバック関数を呼び出す機能を持っています。しかし、watchEffectが呼び出されるタイミングはリアクティブな変数が初期化される前でも後でもあり得ます。このため、変数の初期化が完了する前にwatchEffectが呼び出された場合、その時点では変数はまだ初期化されていないため、undefinedやnullなどの予期しない値を使用することになります。
例えば、以下のようにwatchEffectでリアクティブ変数を監視するとします。
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0
})
watchEffect(() => {
console.log(state.count)
})
state.count++
この場合、watchEffectのコールバック関数が呼び出される順序は、リアクティブな変数が初期化される前でも後でも構いません。つまり、リアクティブな変数stateが初期化される前にwatchEffectが呼び出された場合、コンソールにはundefinedが出力されます。一方、stateが初期化された後にwatchEffectが呼び出された場合、state.countの値が出力されます。
このように、リアクティブな変数が初期化される前にwatchEffectが呼び出されると、初期値が未定義であるため、watchEffectのコールバック関数で意図しない結果が返される可能性があります。
watchEffectを使用する際の注意点
初期化前の変数を使用する場合、以下のような問題が発生する可能性があります。
- リアクティブな変数が初期化される前にwatchEffectが呼び出されるため、変数の初期値が未定義である場合、エラーが発生する可能性があります。
- リアクティブな変数が初期化される前にwatchEffectが呼び出されるため、変数の初期値を使用して意図しない動作が発生する可能性があります。
watchEffectでリアクティブな変数を使う方法
watchEffectを使用する場合は、リアクティブな変数が初期化された後に呼び出されるようにする必要があります。初期化前の変数を使用する場合は、初期化後に値を再設定するか、watchEffectの代わりにwatchやcomputedを使用した方が良いです。
リアクティブな変数が初期化された後に呼び出されるようにするためには、以下のような方法が考えられます。
setup()関数の中で使用する
setup()関数は、コンポーネントが初期化される前に呼び出されるため、リアクティブな変数が初期化された後にwatchEffectを使用することができます。
import { reactive, watchEffect } from 'vue'
export default {
setup() {
const state = reactive({
count: 0
})
watchEffect(() => {
console.log(state.count)
})
return {
state
}
}
}
onMounted()フックで使用する
onMounted()フックは、コンポーネントがマウントされた後に呼び出されるため、リアクティブな変数が初期化された後にwatchEffectを使用することができます。
import { reactive, watchEffect, onMounted } from 'vue'
export default {
setup() {
const state = reactive({
count: 0
})
onMounted(() => {
watchEffect(() => {
console.log(state.count)
})
})
return {
state
}
}
}
これらの方法を使用することで、リアクティブな変数が初期化された後にwatchEffectを呼び出すことができます。初期化前の変数を使用しないように注意して使いましょう💦
まとめ
以上、述べてきたようにwatchEffectを使用する際に、初期化前の変数を使用すると意図しない動作を引き起こす可能性があります。そのため、リアクティブな変数が初期化された後にwatchEffectを呼び出すことが重要です!
参考文献
Discussion