## 事象
以下のようなコードを考える。
```html
<script setup lang="ts">
import { ref, watch } from "vue";
const inputEl = ref<HTMLInputElement | null>(null);
const showInput = ref(false);
watch(
() => showInput.value,
(show) => {
if (show) {
console.log(inputEl.value);
inputEl.value?.focus();
}
},
);
</script>
<template>
<div style="display: flex; gap: 8px; padding: 12px">
<input type="checkbox" v-model="showInput" />
<label>Inputを表示する</label>
</div>
<div style="padding: 12px">
<div v-if="showInput"><input ref="inputEl" /></div>
</div>
</template>
```
![[2024-08-26-00-06-19.webm]]
チェックを入れたらinput欄が表示されるが、`watch`の中で書いた`inputEl.value?.focus()`が実行されない。直前の`console.log`は`null`を出力している。
なお、直前に`await sleep(100)`のようにwaitを入れれば動作する。
## 原因
[[Vue]]では[[DOM]]の更新は非同期で行われるため、`showInput.value`の値が変更されたことを検知した時点では、inputタグが存在するとは限らないため。`await sleep(100)`で動作するのは、その間に[[DOM]]の更新が行われたから。
## 解決方法
[[nextTick()]]を利用する。これは[[DOM]]の更新を待つための非同期関数である。
```html
<script setup lang="ts">
import { nextTick, ref, watch } from "vue";
const inputEl = ref<HTMLInputElement | null>(null);
const showInput = ref(false);
watch(
() => showInput.value,
async (show) => {
if (show) {
// showInputの変更によるDOM更新が終わるのを待つ
await nextTick();
// inputタグが出現しているのでfocusは実行される
inputEl.value?.focus();
}
},
);
</script>
<template>
<div style="display: flex; gap: 8px; padding: 12px">
<input type="checkbox" v-model="showInput" />
<label>Inputを表示する</label>
</div>
<div style="padding: 12px">
<div v-if="showInput"><input ref="inputEl" /></div>
</div>
</template>
```
![[2024-08-26-00-12-23.webm]]
## 参考
- https://ja.vuejs.org/api/general#nexttick