Vueにおけるデータ変更後のDOM操作を安全に実行するnextTickの活用

1. nextTickの役割と目的

nextTickは、Vueがデータ変更を検知してDOMを再レンダリングした直後のタイミングでコールバック関数を実行するためのユーティリティです。Vueのリアクティブシステムは非同期でDOM更新をバッファリングするため、データを変更しても即座にDOMが反映されません。このギャップを埋めるのがnextTickであり、正確なDOM状態を前提としたJavaScript操作(例:フォーカス設定、サイズ取得、プラグイン再初期化)を確実に行うために不可欠です。

2. 動作メカニズムの概要

Vueはデータの変更を検知すると、その更新を「キュー」に登録し、同一イベントループ内で複数回発生した変更を1回のDOM更新に集約します。これはパフォーマンス最適化のための設計です。しかし、開発者が「変更直後にDOMを操作したい」という要件を持つ場合、そのキューが処理された後のタイミングを明示的に待つ必要があります。this.$nextTick()は、そのキューの消化完了を保証し、DOMが実際に更新された直後のマイクロタスクまたはマクロタスクで指定された処理を実行します。

3. 実践的な使用例

例1:動的要素へのフォーカス制御

データ更新後にref経由で要素にフォーカスを当てる場合、単純な呼び出しでは失敗します。
<template>
  <input v-if="showInput" ref="textInput" type="text" />
  <button @click="toggleAndFocus">表示・フォーカス</button>
</template>

<script>
export default {
  data() {
    return { showInput: false };
  },
  methods: {
    toggleAndFocus() {
      this.showInput = true;
      // ❌ 即座に呼び出すとrefはまだ存在しない(または未マウント)
      // this.$refs.textInput?.focus();

      // ✅ DOM更新完了後に実行
      this.$nextTick(() => {
        const el = this.$refs.textInput;
        if (el) el.focus();
      });
    }
  }
};
</script>

例2:createdフック内での安全なDOMアクセス

createdではテンプレートがまだマウントされていないため、ref$elは利用できません。DOM操作が必要な場合は、必ずnextTickでラップします。
export default {
  created() {
    // この段階ではDOMツリーは構築されていない
    this.$nextTick(() => {
      // ✅ 正しくマウントされた後のDOMにアクセス可能
      const button = this.$refs.actionButton;
      if (button) button.textContent = '初期化済み';
    });
  }
};

例3:外部ライブラリとの連携(例:Chart.js再描画)

コンポーネントの状態変更によりチャートのデータが更新された後、チャートインスタンスを再描画する必要がある場合:
data() {
  return {
    chartData: [10, 20, 30],
    chartInstance: null
  };
},
methods: {
  updateChartData(newValues) {
    this.chartData = newValues;
    // データ更新後にチャートを再描画
    this.$nextTick(() => {
      if (this.chartInstance && typeof this.chartInstance.update === 'function') {
        this.chartInstance.update();
      }
    });
  }
}

タグ: Vue reactivity nexttick dom-manipulation lifecycle-hooks

7月2日 20:12 投稿