9.

【Vue.js】$nextTickの使い方(ライフサイクルフック)

編集
この記事の要点
  • $nextTickDOM 反映後に処理を実行する Vue.js のメソッド
  • data を変更しただけだと DOM はまだ更新されていない
  • this.$nextTick(() => ...) で次の DOM 反映タイミングを待つ
  • Vue 3 Composition API: import { nextTick } from "vue" + await nextTick()
  • 用途: DOM サイズ計算 / scroll 位置調整 / サードパーティライブラリ初期化

 

なぜ nextTick が必要か

Vue は data 変更を検知すると次のティックで DOM を更新します(バッチ処理によるパフォーマンス最適化)。data を変更した直後に DOM を参照しても、まだ更新されていません。

// 例: nextTick なしだと
data() {
    return { message: "" };
},
methods: {
    update() {
        this.message = "Hello";
        // この時点で this.$el.textContent は "" のまま!(DOM はまだ更新されていない)

        const len = this.$el.querySelector("p").textContent.length;
        console.log(len);  // → 0
    }
}

nextTick で DOM 反映を待つ

// Vue 2 / Vue 3 Options API
methods: {
    update() {
        this.message = "Hello";

        this.$nextTick(() => {
            // DOM 反映完了後
            const len = this.$el.querySelector("p").textContent.length;
            console.log(len);  // → 5
        });
    }
}

// async / await でも書ける
methods: {
    async update() {
        this.message = "Hello";
        await this.$nextTick();
        const len = this.$el.querySelector("p").textContent.length;
        console.log(len);
    }
}

Vue 3 Composition API



典型的な使用シーン

① 動的に追加した要素のサイズ計算

async addItem(item) {
    this.items.push(item);  // リストに追加
    await this.$nextTick();
    // 新しい要素の高さを計算
    const newElem = this.$refs.list.lastElementChild;
    const height = newElem.getBoundingClientRect().height;
    console.log("追加した要素の高さ:", height);
}

② スクロール位置の調整

async scrollToBottom() {
    this.messages.push({ text: "新メッセージ" });
    await this.$nextTick();
    // メッセージが描画されてからスクロール
    const container = this.$refs.messageContainer;
    container.scrollTop = container.scrollHeight;
}

③ フォーカス制御

async toggleEditMode() {
    this.editing = true;  // v-if で input 表示
    await this.$nextTick();
    // input が描画されてからフォーカス
    this.$refs.editInput.focus();
}

④ サードパーティライブラリの再初期化

async updateChart() {
    this.chartData = newData;
    await this.$nextTick();
    // Chart.js を再描画
    this.chart.update();
}

async refreshSlider() {
    this.slides = newSlides;
    await this.$nextTick();
    // Swiper を再初期化
    this.swiper.update();
}

watch との組み合わせ

// Vue 3 Composition API
import { watch, nextTick, ref } from "vue";

const items = ref([]);

watch(items, async (newItems) => {
    await nextTick();
    // items が変更されて DOM が更新された後
    console.log("DOM 更新完了");
});

nextTick が複数回ある場合

同じティック内の複数の data 変更は1 回の DOM 更新にまとめられます:

methods: {
    async updateMany() {
        this.a = 1;
        this.b = 2;
        this.c = 3;
        // すべての変更が 1 回の DOM 更新で反映される
        await this.$nextTick();
        // 全部反映済み
    }
}

nextTick の代替

シンプルなケースなら setTimeout(fn, 0)requestAnimationFrame でも近い動作になりますが、Vue の更新サイクルと完全に同期する保証はないため nextTick を使うのが安全:

// ✗ 動くこともあるが、Vue の更新と同期しないことも
this.message = "Hello";
setTimeout(() => {
    console.log(this.$el.textContent);
}, 0);

// ✓ 確実
this.message = "Hello";
this.$nextTick(() => {
    console.log(this.$el.textContent);
});

注意点

無限ループに注意

// ✗ 危険
async update() {
    this.count++;
    await this.$nextTick();
    this.count++;  // また data 変更 → さらに DOM 更新サイクル
    // → updated フックや watcher で意図せず連鎖発火することがある
}

テストでも nextTick

// Vue Test Utils
import { mount } from "@vue/test-utils";
import { nextTick } from "vue";

test("counter increments", async () => {
    const wrapper = mount(Counter);
    await wrapper.find("button").trigger("click");
    await nextTick();  // DOM 反映を待つ
    expect(wrapper.text()).toContain("Count: 1");
});

関連記事

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. インストール(ファイルのダウンロード)
  2. npmを使用したプロジェクトの作成(mac)
  3. for 繰り返し処理
  4. ifの条件分岐とtemplateを用いたグループ化
  5. on:click クリック時のイベント処理
  6. modelとdata フォーム入力値とDOMへの即時反映
  7. computed(算出プロパティ)と使い方とdataとの違い
  8. ライフサイクルフック(created / mounted / updated / destroyedの使い方)
  9. $nextTickの使い方(ライフサイクルフック)
  10. メソッドの定義方法
  11. エラー一覧
  12. ルーティング設定
  13. aリンクの貼り方と動的URLの作成
  14. Mixinを利用した共通処理の記述方法
  15. v-bindによるデータ連携
  16. ヘッダー/フッターの共通コンポーネント
  17. ナビゲーションの現在ページをハイライトする方法
  18. 画面サイズの取得方法