みなさん、Vue v3(vue-next)使ってますか?私は使ってません。
Vue v2にComposition Apiパッケージを導入して雰囲気を楽しんでいます。
Composition API v0.5.0で追加されたwatchEffect関数をご存知でしょうか。
実はもう2ヶ月ほど前に追加されてますが私はつい先日触ったのでここに書いておこうと思います。
Vue v2のwatch
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
皆さんに馴染みがあるのはこのwatchではないでしょうか。
firstName
とlastName
の変数を監視して、変更があった場合に別の変数を更新する。
しかし、この場合は公式ページでも書かれているようにcomputed
を使ったほうが良いでしょう。
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
なので、watch
を使う場合は何らかの変数の変更を検知して他の処理を行いたい場合に使うことが多く、このように別の変数に入れ直す場合はcomputed
、算出プロパティを使うのが良いと思います。
この辺は公式ページで丁寧に説明されてるのでおさらい程度で。
Vue v3のwatch
Vue v3もとい、CompoisitionAPI(v0.5.0以降)はwatch
とwatchEffect
の2つのウォッチャーを提供しています。
setup() {
const hoge = ref('')
watch(
() => hoge,
(hoge) => {
somethingMethod(hoge)
}
)
}
第一引数に監視対象、第二引数に変更を検出した際に実行したい関数を定義できます。
ほとんどv2と変わらない感じですね。
複数の監視対象にも対応していて次のように配列で渡すこともできます。
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})
もうちょっと詳細に型定義を見てみると
// wacthing single source
function watch<T>(
source: WatcherSource<T>,
callback: (
value: T,
oldValue: T,
onInvalidate: InvalidateCbRegistrator
) => void,
options?: WatchOptions
): StopHandle
// watching multiple sources
function watch<T extends WatcherSource<unknown>[]>(
sources: T
callback: (
values: MapSources<T>,
oldValues: MapSources<T>,
onInvalidate: InvalidateCbRegistrator
) => void,
options? : WatchOptions
): StopHandle
type WatcherSource<T> = Ref<T> | (() => T)
type MapSources<T> = {
[K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never
}
// see `watchEffect` typing for shared options
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // default: false
deep?: boolean
}
StopHandle
を返り値としているので以下のように監視を停止することができます。
setup() {
const hoge = ref('')
const stop = watch(
() => hoge,
(hoge) => {
somethingMethod(hoge)
}
)
stop()
}
監視対象のオブジェクトが階層化していて、そのすべての変更検出したい場合もあるかと思います。
setup() {
const hoge = reactive({
fuga: {
piyo: true,
hogera: false,
},
hogehoge: false
})
watch(
() => hoge,
() => {},
{ deep: true }
)
}
この場合、watch関数の第三引数、WatchOptions
でdeep: true
と指定することで実現できます。
watchEffect
Composition API v0.5.0で追加されたwatchEffect
はwatch
とは異なり、callback
内部にあるオブザーバブル値を検出して実行されます。
setup() {
const hoge = ref('')
watchEffect(() => {
somethingMethod(hoge.value)
})
}
watchに比べると監視対象を明示的に宣言していないので簡略して書けますが、何がトリガーで実行されてるかがわかりにくいという反面もあります。
また、複数のオブザーバブルな値が入る場合には注意が必要で
setup() {
const hoge = ref('')
const fuga = ref('')
watchEffect(() => {
fuga.value = somethingMethod(hoge.value)
})
}
このように別のリアクティブ変数に入れ直す処理を書いた場合に、fuga
変数の変更も監視されてwatchEffect
が実行されるのでおそらく無限ループされます。
こういう場合はfuga
をcomputed
にするか、watch
を使うと良いと思います。
型定義はこちら
function watchEffect(
effect: (onInvalidate: InvalidateCbRegistrator) => void,
options?: WatchEffectOptions
): StopHandle
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}
type InvalidateCbRegistrator = (invalidate: () => void) => void
type StopHandle = () => void
より詳細な情報は公式を見てください。
Vue v3楽しみですね。