логотип PurpleSchool
логотип PurpleSchool

Использование ref для управления ссылками и реактивностью в Vue 3

Автор

Олег Марков

Введение

В Vue 3 одним из главных нововведений стал Composition API — новый способ организации реактивности и управления состоянием компонентов. Одним из важных элементов Composition API является функция ref. Она выступает как универсальный инструмент для создания реактивных данных и получения ссылок на элементы DOM.

Использование ref позволяет создавать реактивные примитивы (например, числа, строки, логические значения) и удобно работать с ними в реактивном контексте. Помимо этого, ref открывает дополнительные возможности по ссылкам на HTML-элементы, что важно для манипуляций DOM в рамках шаблонов.

Давайте вместе разберёмся, как устроен ref, где и как его рационально применять, с какими особенностями его использования стоит знакомиться разработчикам Vue 3.

Что такое ref и зачем он нужен

Основы синтаксиса и концепция

В Vue 3 Composition API, чтобы сделать переменную реактивной, вы вызываете функцию ref(value), передавая в неё исходное значение. Возвращается реактивный объект, который можно безопасно использовать и изменять, не теряя реактивности.

Давайте посмотрим простой пример:

import { ref } from 'vue'

export default {
  setup() {
    // Создаём реактивное число с начальными данными 0
    // count теперь объект типа Ref
    const count = ref(0)

    // В шаблоне мы сможем обращаться к count, чтобы отобразить его
    return { count }
  }
}

ref удобно использовать для реактивных примитивов, например, для счетчиков, флагов, строк, которые не получится сделать реактивными с помощью reactive (этот способ лучше подходит только для объектов и массивов).

Reactivity и значение .value

В отличие от обычных переменных, чтобы получить или задать значение для ref-переменной, нужно обращаться к свойству .value. Единственное исключение — шаблон компонента, внутри которого Vue автоматически прокидывает это свойство.

Пример:

const count = ref(0)

console.log(count.value) // Получаем текущее значение
count.value++            // Изменяем его

В шаблоне делать это вручную не нужно:

<template>
  <button @click="count++">Clicked {{ count }} times.</button>
</template>

Создание реактивных переменных с ref

Примитивные значения

Когда вы хотите создать реактивную переменную для числа, строки, булевого значения, используйте ref:

const message = ref('Привет, мир!')
const flag = ref(false)
const score = ref(10)

Теперь при изменении .value этих переменных связанные части шаблона автоматически обновятся.

Массивы и объекты

Ref также поддерживает работу с объектами и массивами. Но есть нюансы! Когда вы кладёте в ref объект или массив, сам контейнер остаётся ref, и обращаться к данным следует через .value, а его внутренности Vue делает реактивными автоматически.

Смотрите, как это выглядит:

const user = ref({
  name: 'Мария',
  age: 23
})

// Изменяем реактивные свойства через .value
user.value.name = 'Игорь'
user.value.age++

Этот подход жизненно важен тогда, когда ваш объект может быть полностью заменён.

Особенность: ref и reactive

Если вы используете только объекты — есть альтернатива: reactive сразу делает объект реактивным без обёртки .value:

import { reactive } from 'vue'
const state = reactive({ count: 0, theme: 'light' })

state.count++ // Работает напрямую

Но если объект может быть заменён целиком или это примитив — выбирайте ref. Также ref в любом случае универсальнее: его всегда можно использовать как в JS-коде, так и в шаблоне, где "из коробки" разворачивается без необходимости указывать .value.

Использование ref для доступа к DOM-элементам

ref играет особую роль в работе с DOM, ведь иногда в шаблоне нужно получить доступ к конкретному элементу: например, сфокусировать input, измерить его размеры, среагировать на событие, для которого не хватает обычных слушателей.

Давайте разберём пример.

Как получить ссылку на DOM-узел

  1. Создайте переменную с помощью ref без значения:
const inputRef = ref(null)
  1. Свяжите её с элементом через директиву ref в шаблоне:
<input ref="inputRef" />
  1. Теперь доступно свойство .value, содержащее DOM-элемент после монтирования компонента:
onMounted(() => {
  if (inputRef.value) {
    inputRef.value.focus() // Установим фокус сразу
  }
})

Динамическое управление элементами

ref работает и для массивов или компонентов (например, при рендеринге v-for):

<div v-for="(item, idx) in list" :key="item.id" :ref="setItemRef"></div>

В JS-коде:

const itemRefs = ref([])

function setItemRef(el) {
  if (el) itemRefs.value.push(el)
}

Вот здесь очень важно: хранить DOM-элементы или компоненты через ref, иначе Vue не сможет правильно отслеживать изменения, особенно при динамическом удалении или добавлении элементов.

Reactivity: особенности реактивности ref

Как ref работает «под капотом»

Vue 3 реализует реактивность через прокси-объекты, которые перехватывают чтение и запись значения. Когда вы используете ref, он создаёт объёртку с геттером/сеттером для .value. Это даёт возможность засечь изменение — и запустить обновление компонента, если переменная участвует в вычислениях или шаблоне.

Автоматическое «разворачивание» в шаблонах

В шаблоне компонента обращаться к ref можно без .value:

<span>{{ count }}</span> <!-- автоматически count.value -->

Всё происходит автоматически, Vue это делает ради удобства и совместимости.

Реактивность и объекты-массивы внутри ref

К примеру:

const arr = ref([1, 2, 3])
arr.value.push(4) // Это изменение тоже вызовет обновление!

Это удобно — Vue отслеживает изменения как структуры .value, так и её содержимого.

Использование с вычисляемыми и наблюдаемыми значениями

Работу с ref можно комбинировать с computed и watch:

const count = ref(0)

const doubleCount = computed(() => count.value * 2)

watch(count, (newVal, oldVal) => {
  console.log('count изменился:', oldVal, '→', newVal)
})

В этом примере вы видите, что ref прекрасно встраивается в полноценную реактивную связку приложения: его можно наблюдать, вычислять на основе него производные значения и всё это всегда будет согласовано.

Возможности ref в Composition API

Передача ref между компонентами

Вы можете передавать ref в дочерние компоненты:

// Родитель
<ChildInput :inputRef="inputRef" />

// Дочерний компонент
props: {
  inputRef: Object
},
mounted() {
  this.inputRef.value.focus()
}

Это очень удобно, если нужно сфокусировать элемент или получить ссылку на него из родителя.

Совместное использование с шаблонной ссылкой

Vue позволяет вызывать несколько ссылок через ref, комбинируя Composition API и шаблонные рефы. Заметим, что доступ к DOM появится только после хуков mounted или updated.

Управление коллекциями DOM-узлов

Если работаете с v-for и директивой ref, сохранять коллекцию объектов ещё важнее. Для этого чаще всего используют массив или объект:

const items = ref([])

function setItemRef(el, idx) {
  if (el) items.value[idx] = el
}

Шаблон:

<div v-for="(item, idx) in list" :ref="el => setItemRef(el, idx)">
  {{ item.name }}
</div>

Теперь вы свободно распоряжаетесь ссылками на все элементы списка.

Советы и "подводные камни" при работе с ref

1. Никогда не используйте ref без .value в коде JS

За пределами шаблона всегда обращайтесь к свойству .value! Так вы гарантируете корректную реактивность данных.

2. Именование переменных

Для ref переменных часто используют суффикс Ref или префикс is для булевых значений, например: countRef, inputRef, isLoading.

3. Не изменяйте напрямую свойство value в шаблоне с помощью выражений

Лучше всё управление оставить для JS-кода или событий, чтобы избежать непредсказуемого поведения.

4. Разница между ref и reactive для объектов

ref идеально подходит для реактивных примитивов и случаев, когда объект должен заменяться полностью (myObj.value = {...}). reactive хорошо работает, если нужно модифицировать значения объекта напрямую.

5. Не используйте ref только ради передачи данных

Если переменная не изменяется и не привязывается к реактивности/DOM, используйте обычную переменную/props.

Заключение

Функция ref — это не только ключевой механизм работы Composition API в Vue 3, но и практичный инструмент для гибкой работы с состоянием компонентов и ссылками на DOM. Благодаря ref можно просто объявлять реактивные данные, безопасно модифицировать их и отслеживать изменения, комбинировать с другими реактивными инструментами, а также легко управлять доступом к компонентам и элементам разметки.

Когда вы поймёте, как именно рефы устроены "под капотом" и освоите практику их использования, ваши компоненты станут проще, а приложение — надёжнее и гибче.


Частозадаваемые технические вопросы по теме статьи и ответы на них

Какие типы значений нельзя делать реактивными с помощью ref?

С помощью ref нельзя сделать реактивными несерийные типы вроде функций или Symbol. Кроме того, ref не сделает реактивными изменения, происходящие внутри встроенных объектов вроде Map, Set или Date. Если нужно хранить функцию в состоянии, используйте обычную переменную.

Как «обернуть» сторонний объект так, чтобы его свойства стали реактивными через ref?

Если нужно, чтобы свойства были реактивными, лучше использовать reactive. Например: js const apiData = reactive(externalObject) Однако если требуются только замены или отслеживание ссылок на весь объект, ref подойдёт больше.

Как очистить ссылку ref на DOM-элемент при его удалении?

Vue сам очищает свойства ref, когда элемент удаляется. В JS-коде достаточно проверять ref.value на null: js if (elRef.value) { // Элемент существует } После удаления elRef.value станет null.

Можно ли прокидывать ref через provide/inject?

Да, Vue допускает передачу рефов через provide/inject, что удобно для глобальных ссылок или состояний: js provide('myRef', myRef) const myRef = inject('myRef')

Как отслеживать изменения внутри массива/объекта, сохранённого в ref?

Vue автоматически отслеживает добавление, удаление, изменение свойств массивов и объектов внутри ref: js const arr = ref([]) watch(arr, () => { /* реагирует на любые изменения */ }) Для глубокой слежки используйте опцию { deep: true }, если требуется: js watch(arr, handler, { deep: true })

Стрелочка влевоРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование Vue Pro и его преимущества для профессиональной разработкиСтрелочка вправо

Постройте личный план изучения Vue до уровня Middle — бесплатно!

Vue — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Vue 3 и Pinia

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий