Vue.jsにおいて、リアクティブなデータ(例:`isVisible = true`)を変更し、新しく表示されたDOM要素(`<input>`など)に対して即座にフォーカスを当てたいと考えています。このとき、意図した通りに動作する実装方針とその理由として正しいものはどれですか?
解説
正解は「データの値を変更した後、nextTickを待ってからfocus()を実行する。Vueはパフォーマンス最適化のためDOMの更新を非同期(Asynchronous)に行うため」です。Vueはリアクティブなデータを変更した際、その変更を即座に画面(DOM)へ反映するわけではありません。同じイベントループ内で発生した複数のデータ変更をまとめ、非同期に一度だけDOMを更新します。そのため、データ変更直後にDOMにアクセスしようとしても、古い状態のままであり要素が見つからずエラーになります。nextTickは、この「DOMの更新が完了した直後のタイミング」を保証するユーティリティ機能です。VueはなぜDOMをすぐに更新しないのかVueが「データが変わったら即DOMを書き換える」という同期的な処理を行わない最大の理由は、パフォーマンスの最適化です。たとえば1つのメソッド内で count.value を1000回更新した場合、都度DOMを描画し直すとブラウザのレンダリング処理が追いつかず、画面がフリーズしてしまいます。そのためVueは内部でキュー(処理の待ち行列)を作り、「次のサイクル(Tick)」でまとめて一度だけDOMに反映します。これがDOMの非同期更新の仕組みです。nextTickの実務での使いどころとコード例実務において「データ更新後にDOM要素の高さを取得したい」「新しく表示された入力フォームにフォーカスを当てたい」といった場面で nextTick が活躍します。具体的なコード例を見てみましょう。<template> <div> <button @click='showInput'>入力欄を表示</button> <input v-if='isVisible' ref='myInput' /> </div> </template> <script setup> import { ref, nextTick } from 'vue'; const isVisible = ref(false); const myInput = ref(null); const showInput = async () => { isVisible.value = true; // ここではまだDOMにinputが存在しないためエラーになる // myInput.value.focus(); // DOMの更新を待つ await nextTick(); // DOMが更新されたので安全にフォーカスできる myInput.value.focus(); }; </script>このように、async/awaitと組み合わせて await nextTick() と書くのがモダンなVueの書き方です。初学者のうちは「なんとなく setTimeout で遅らせたら動いた」という実装をしてしまいがちですが、VueのライフサイクルとDOMの更新サイクルを正しく理解し、nextTick を適切に使いこなすことが中堅エンジニアへの第一歩です。