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Для импорта компонентов
CДля объектов и массивов — он делает их реактивными без обёртки .value
DДля обработки событий
3. Какая практичная рекомендация по умолчанию для нового кода на Vue 3?
AИспользовать только reactive, чтобы не писать .value
BЧередовать ref и reactive случайным образом
CХранить состояние в обычных переменных let
DИспользовать ref почти везде — тогда правило одно: в скрипте всегда .value