新しく追加された機能(2)
Teleportコンポーネントに導入されたdefer属性
次に紹介するのは、Teleportコンポーネントに新たに導入されたdefer属性(defer prop)です。
Teleportコンポーネントは、モーダルの表示など、コンポーネントの一部の要素を後から表示させる際に便利なコンポーネントです。例えば、リスト6のようなコードです。[表示]ボタンをクリックすると、showOrNotの値がtrueへと変化し、(2)のdiv要素がレンダリングされるだけではなく、そのレンダリング先も、(1)のTeleportコンポーネントのおかげで、id属性がteleportBoxの要素内となります。
<script setup lang="ts">
const showOrNot = ref(false);
const onShowButtonClick = () => {
showOrNot.value = true;
}
</script>
<template>
<section>
<button v-on:click="onShowButtonClick">表示</button>
</section>
<Teleport to="#teleportBox"> // (1)
<div v-if="showOrNot"> // (2)
: // (2)
</div> // (2)
</Teleport>
</template>
しかし、従来はこのTeleportコンポーネントのマウント時に制約がありました。表示先要素、すなわち、リスト6ならば、idがteleportBoxの要素がすでにレンダリングされている必要があったのです。もし、表示先要素が存在しない、すなわちnullの場合は、図3のような警告がコンソールに表示されます。さらに、実際にTeleportコンポーネント内の要素を表示させる、すなわち、リスト6ならば、[表示]ボタンをクリックすると、エラーとなり表示されません。
このような制約をなくすために、バージョン3.5で導入されたのが、defer属性(prop)です。リスト6の(1)を次のように記述すると、図3の警告は表示されなくなり、[表示]ボタンをクリックしたら、idがteleportBoxの要素内に(2)のdiv要素が無事レンダリングされます。
<Teleport defer to="#teleportBox">
このカラクリは、defer属性の記述されたTeleportコンポーネントが、対象要素(リスト6ならばidがteleportBoxの要素)がレンダリングするまで、マウントするのを待つようになるからです。
ウォッチャーのクリーンアップを行うonWatcherCleanup()
watch()関数やwatchEffect()関数といった、いわゆるウォッチャーが連続して実行された際に、ウォッチャー内の処理のクリーンアップ処理を簡単に登録できるコールバックとして、onWatcherCleanup()関数がバージョン3.5で新たに導入されました。このonWatcherCleanup()を導入したウォッチャーは、例えば、リスト7のコードとなります。
watch(countDownTime, // (1)
(newValue, oldValue) => {
onWatcherCleanup( // (2)
() => {
clearInterval(intervalId); // (3)
}
);
timeLeft.value = countDownTime.value; // (4)
const intervalId = setInterval(
() => {
if(timeLeft.value > 0) {
timeLeft.value--;
}
else {
clearInterval(intervalId);
}
},
1000
);
}
);
リスト7の例は、画面に入力された秒数(countDownTime)を元に、timeLeftをカウントダウンする処理コードです。実際のカウントダウン処理は、(4)以降、特にsetInterval()による処理です。この処理コードが、countDownTimeの値が変更するたびに行われます。そのため、(1)のようにcountDownTimeが監視対象となっています。
ここで問題となるのは、このカウントダウン処理が完了する前、監視対象であるcountDownTimeの値が変化した場合です。その場合、(4)以降の新たなカウントダウン処理をそのまま実行するわけにはいかず、いったんカウントダウン処理をキャンセルする必要があります。
そういったキャンセル処理を定義できるのが、(2)のonWatcherCleanup()であり、(3)のclearInterval()の実行がキャンセル処理そのものです。このonWatcherCleanup()が定義されたウォッチャーは、(4)以降の本来の処理を実行する前に、必ず(3)の処理が呼び出されるようになっています。
なお、リスト7では、ウォッチャーのアロー関数内の最初にonWatcherCleanup()を記述していますが、この記述位置はアロー関数内ではどこでも問題ありません。どこに記述しても、その処理はウォッチャーが再実行される直前に必ず実行されます。
