## 事象 以下のようなコードを考える。 ```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