
ブログをNext.js14(App Router)でリファクタリングしました
Vue3.2の時点でwatch系の関数はwatch / watchEffect / watchPostEffect / watchSyncEffectの4種類あります。
それぞれの意味と違いをご存知でしょうか。今回はこの4種類のwatchについて解説していきます。
また、複数の値を監視するwatchやネストされた値の監視、watchの実行タイミングについても解説しています。
watch系の関数は全部で以下の4種類存在します。
この記事では、上記4つのwatchについて解説していきます。
4つのwatchを挙げましたが、大きく分けると watch と watchEffect系の2種類に分類されます。
残りのwatchPostEffect、watchSyncEffectの2つは 、watchEffectのオプションに{ flush: 'post'}
、{ flush: 'sync' }
というオプションを付けた単なるエイリアス(別名)です。
つまり、watchEffectだけで書き換えることが可能です。これらのオプションの意味についても追って解説します。
それではまず、watchEffectから解説します。
配下のコールバック関数内で参照している変数の、いずれかが変化する度に実行される関数です。
つまり、複数の値を監視しています。
・基本構文
watchEffect(() => {
//変数A
//変数B
//このコールバック内に書いてある変数は全て監視の対象
})
上のコードでは変数Aと変数Bを配下に置いています。
それぞれの変数は監視されており、どちらか一方にでも変化があれば、watchEffectが実行されます。
次のコードでは、クリックイベントが発生する度に変数numが加算され、
それを監視しているwatchEffectも実行される例です。
const num = ref(0)
const onClick = () => num.value++ //クリックアクション
watchEffect(() => {
console.log(num.value) //onClickが呼ばれるたびに呼び出される
})
watchEffectの実行タイミング(フラッシュ)は3種類のうちから指定して制御できます。
①pre、②sync、③postの3種類があります。
これをwatchEffectの第2引数のflushプロパティに指定します。
watchEffect(() => {
//
},{
flush: "sync" //or "post" or "pre"
})
それぞれの実行タイミングについて詳しく解説します。
デフォルト値です。コンポーネント更新前に非同期で呼ばれます。
つまり、ライフサイクルの中では、beforeUpdate前に呼び出されます。
コンポーネント更新前、すなわちbeforeUpdate前に、同期的に、すぐさま呼び出します。
ただし、watchEffectを同期的に呼び出すのは効率が悪いので、あまりおすすめされません。
大体はpreよりも先に呼び出されることになります。
コンポーネント更新後に呼び出されます。 beforeUpdate〜updatedのタイミングです。
ライフサイクルフックとの実行順序の関係をまとめると、次のようになります。
sync → pre → onBeforeUpdate → post → onUpdated
これら2つは、前節で紹介したflushのタイミングを、sync、postに設定しただけのwatchEffectの別名に過ぎません。ですので、効果は全く同じです。
watchも値を監視する関数ですが、次の点でwatchEffectとは異なります。
watch(監視対象, (次の状態, 前の状態) => {
//
} )
監視対象には監視したいプリミティブ型や配列等を指定しますが、種類によって記述方法を変える必要があります。
次の状態、前の状態には監視している値の変更前後の値が渡されます。
以下に、監視対象のデータ型の違いによる記述の方法を説明します。
値をそのまま代入すれば大丈夫です。
const num = ref(0)
watch(num, (next, prev) => {
//
} )
配列のコピーを返す関数を代入します。
const ary = ref<number[]>([])
watch(() => [...ary.value], (next, prev) => {
//
} )
オブジェクトのコピーを返す関数を代入します。
const state = reactive({count : 0, age: 0})
watch(() => ({...state}), (next, prev) => {
//
} )
配列でまとめて複数要素を渡せば、複数要素の監視ができます。
ただし注意点が1つあります。
配列で渡した要素のうちいずれか1つが変更されればwatchが発火しますが、同時に変更されても発火は1回しか起こりません。
//同時に変更
const onClick = () => {
++num1.value
++num2.value
}
//発火は1回
watch([num1, num2], ([nextNum1, nextNum2], [prevNum1, prevNum2]) => {
//
})
この場合は、nextTickを用いて次のtickを待てば良いです。
//同時に変更
const onClick = async () => {
++num1.value
await nextTick()
++num2.value
}
//それぞれ1回ずつ計2回発火
watch([num1, num2], ([nextNum1, nextNum2], [prevNum1, prevNum2]) => {
//
})
deep: trueプロパティをつければ、ネストが深いオブジェクトに対してもwatchが働きます。
リアクティブなオブジェクトをそのまま代入することも可能です。
const state = reactive({
age: 0,
type: {
hoge: 0
}
})
watch(() => state, (next, prev) => {
//
},
{
deep: true
})
immidiate: trueプロパティをつければコンポーネント作成時にもwatchが実行されます。
watchEffect同様、①pre、②sync、③postの3種類をflushプロパティで指定します。
4種類のwatchについて解説しました。そのうちwatchSyncEffectとwatchPostEffectはwatchEffectの単なるエイリアスなので、基本的にはwatchとwatchEffectさえおさえておけば良いでしょう。これらの違いは実行タイミングのみです。watchはwatchEffectよりも多機能な分記述も長くなるので、使い分けが大事です。
最新の記事
カテゴリー一覧
アーカイブ