ref и reactive: два способа хранить состояние

Разбираем главную развилку реактивности Vue 3 — ref против reactive: как они устроены, зачем ref нужен .value и какой брать в каком случае.

ref делает реактивным любое значение (число, строку, объект), оборачивая его в объект со свойством .value. reactive делает реактивным сам объект целиком, без обёртки.

ref: обёртка над значением

ref подходит для одиночных значений: числа, строки, булевы. Чтобы примитив можно было отслеживать, Vue кладёт его внутрь объекта-обёртки. Реальное значение — в .value:

// Имитируем, как устроен ref: значение лежит в .value
function ref(initial) {
  return { value: initial };
}

const count = ref(0);
console.log("Сейчас:", count.value);
count.value = count.value + 1;
console.log("После +1:", count.value);

Вывод:

Сейчас: 0
После +1: 1

Это и есть причина, по которой в скрипте пишут count.value. В шаблоне же Vue разворачивает ref сам — там пишут просто {{ count }}.

reactive: реактивный объект

reactive работает с объектами и массивами. Он возвращает реактивный прокси — свойства читаются и пишутся напрямую, без .value:

<template>
  <p>{{ user.name }}, возраст {{ user.age }}</p>
  <button @click="user.age++">Старше</button>
</template>

<script setup>
import { reactive } from 'vue'
const user = reactive({ name: 'Аня', age: 25 })
</script>

Когда что выбирать

СлучайБрать
Примитив (число, строка, булево)ref
Объект или массивref или reactive
Нужна единая запись для всегоref везде

Распространённая рекомендация сообщества: используйте ref по умолчанию для всего. Тогда правило простое — «в скрипте всегда .value». Это избавляет от путаницы «здесь с .value, а здесь без». ref с объектом внутри тоже полностью реактивен (Vue применяет reactive к его содержимому автоматически).

ref с объектом

function ref(initial) { return { value: initial }; }

// ref может хранить и объект — тогда меняем через .value
const state = ref({ items: [], total: 0 });
state.value.items.push("молоко");
state.value.total = state.value.items.length;
console.log(state.value);

Вывод:

{ items: [ 'молоко' ], total: 1 }

Главное про различие

  • ref — универсален, но в скрипте требует .value.
  • reactive — только для объектов/массивов, без .value, но с подвохами (о них — следующий урок).

Итог

  • ref(v) оборачивает значение; в скрипте — .value, в шаблоне — без него.
  • reactive(obj) делает реактивным объект целиком, доступ к свойствам напрямую.
  • Практичный выбор по умолчанию — ref везде: единое правило «.value в скрипте».
  • ref с объектом внутри тоже полностью реактивен.
Проверьте себя
1. Почему к значению ref в скрипте обращаются через .value?
AЭто требование TypeScript
Bref — объект-обёртка, и реальное значение хранится в свойстве .value
C.value ускоряет реактивность
DБез .value Vue выдаёт синтаксическую ошибку
2. Для чего лучше всего подходит reactive?
AДля одиночных чисел и строк
BДля объектов и массивов — он делает их реактивными без обёртки .value
CДля импорта компонентов
DДля обработки событий
3. Какая практичная рекомендация по умолчанию для нового кода на Vue 3?
AИспользовать только reactive, чтобы не писать .value
BИспользовать ref почти везде — тогда правило одно: в скрипте всегда .value
CЧередовать ref и reactive случайным образом
DХранить состояние в обычных переменных let
Поддержать проект