> Как получить ref компонента сразу после его отрисовки при условном рендеринге во Vue (Vue.js)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: ЛОЦИЯ

Стек: Vue.js

> Пример ответа

Короткий ответ

При условном рендеринге во Vue ref компонента становится доступен только после монтирования соответствующего узла. Используйте nextTick внутри watch или watchEffect, чтобы дождаться обновления DOM после изменения условия. Альтернатива - использовать v-if с ключом или шаблонные refs с колбэком, который вызывается после монтирования.

Подробное объяснение

Ref компонента во Vue - это реактивная ссылка на DOM-элемент или экземпляр компонента. При условном рендеринге через v-if или v-show узел может отсутствовать в DOM в момент выполнения кода. Vue обновляет DOM асинхронно, поэтому ref заполняется только после того, как Vue завершит рендеринг.

Основные подходы:

  • nextTick - дожидается следующего цикла обновления DOM после изменения реактивных данных.
  • watch с { flush: 'post' } - гарантирует, что колбэк выполнится после обновления DOM.
  • Функциональные refs - колбэк, передаваемый в ref, вызывается при монтировании/размонтировании узла.
  • v-if с key - принудительно пересоздаёт компонент, что может упростить логику.

Для v-show ref всегда существует, но элемент может быть скрыт. Для v-if ref равен null, пока условие ложно.

На практике

В реальных проектах чаще всего используют watch с nextTick или watchEffect с flush: 'post'. Это надёжно и читаемо. Функциональные refs удобны для разовых операций, но усложняют код при множественных условиях.

Пример сценария: модальное окно, которое появляется по условию, и нужно сразу установить фокус на input внутри него.

Пример кода

<template>
  <div>
    <button @click="show = !show">Toggle</button>
    <div v-if="show" ref="myRef">Содержимое</div>
  </div>
</template>

<script setup>
import { ref, watch, nextTick } from 'vue'

const show = ref(false)
const myRef = ref(null)

watch(show, async (newVal) => {
  if (newVal) {
    await nextTick()
    // myRef.value теперь доступен
    console.log(myRef.value?.textContent)
  }
})
</script>

Альтернатива с функциональным ref:

<template>
  <div v-if="show">
    <div :ref="el => { if (el) handleMounted(el) }">Содержимое</div>
  </div>
</template>

<script setup>
const show = ref(false)

function handleMounted(el) {
  console.log(el.textContent)
}
</script>

Как отвечать на собеседовании

Начните с объяснения асинхронной природы Vue и того, что ref заполняется после монтирования. Упомяните nextTick как основной инструмент. Приведите пример с watch и nextTick. Если спросят про v-show, отметьте, что ref существует всегда, но элемент может быть скрыт. Будьте готовы обсудить flush: 'post' и функциональные refs как альтернативы.

Что проверяет интервьюер

  • Понимание жизненного цикла компонентов Vue и асинхронного обновления DOM.
  • Умение работать с реактивностью и refs в условных сценариях.
  • Знание nextTick, watch и watchEffect.
  • Способность выбрать правильный инструмент под задачу.

Типичные ошибки

  • Попытка обратиться к myRef.value сразу после изменения условия без nextTick.
  • Использование v-show вместо v-if без учёта, что ref существует, но элемент скрыт.
  • Забывание, что ref может быть null, если условие ложно.
  • Чрезмерное усложнение с функциональными refs там, где достаточно nextTick.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью