Глубокое и поверхностное отслеживание

Vue.js предоставляет мощный механизм реактивности, основанный на отслеживании изменений данных. Основное различие заключается между поверхностным (shallow) и глубоким (deep) отслеживанием, что существенно влияет на поведение реактивных свойств и вычисляемых эффектов.


Поверхностное отслеживание

Поверхностное отслеживание применяется по умолчанию при создании реактивных объектов с помощью reactive() или ref(). В этом случае Vue отслеживает только изменения на первом уровне свойств объекта.

Пример:

import { reactive, effect } from 'vue';

const state = reactive({
  user: {
    name: 'Alice',
    age: 25
  }
});

effect(() => {
  console.log(state.user.name);
});

state.user.name = 'Bob'; // Вызывает эффект
state.user.age = 26;     // Эффект не сработает

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


Глубокое отслеживание

Глубокое отслеживание позволяет Vue реагировать на изменения всех уровней вложенности объектов и массивов. В стандартном API оно доступно через watch() с параметром { deep: true }.

Пример:

import { reactive, watch } from 'vue';

const state = reactive({
  user: {
    name: 'Alice',
    age: 25
  }
});

watch(
  () => state.user,
  (newValue, oldValue) => {
    console.log('Пользователь изменился', newValue);
  },
  { deep: true }
);

state.user.age = 26; // Срабатывает watch

Особенности глубокого отслеживания:

  • Использует рекурсивное обходное наблюдение.
  • Может снижать производительность при больших и сложных структурах данных.
  • Не всегда необходим, если изменения происходят только на верхнем уровне.

Reactivity API и вложенные объекты

Vue 3 создает реактивность на основе Proxy, что позволяет отслеживать доступ к свойствам и их изменения.

Поведение reactive и ref:

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

Пример:

import { reactive, ref } from 'vue';

const count = ref(0);       // простое число
const user = ref({ name: 'Alice', age: 25 }); // объект внутри ref

count.value++;             // реактивное обновление
user.value.name = 'Bob';   // также отслеживается благодаря реактивности объекта внутри ref

Watch vs Effect

watch и effect используют реактивность по-разному:

  • effect отслеживает любые зависимости, используемые внутри функции, и срабатывает при их изменении.
  • watch позволяет задавать целевое свойство и дополнительные параметры: immediate, deep, flush.

Пример различий:

import { reactive, effect, watch } from 'vue';

const state = reactive({ user: { name: 'Alice', age: 25 } });

effect(() => {
  console.log(state.user.name); // только имя
});

watch(
  () => state.user,
  (newValue) => console.log(newValue),
  { deep: true } // все вложенные изменения
);

Вывод: effect удобен для быстрых вычислений при использовании свойств, а watch нужен для наблюдения и побочных эффектов.


Глубокое копирование и реактивность

Важно помнить, что глубокое копирование не сохраняет реактивность по умолчанию. Использование JSON.parse(JSON.stringify(obj)) создаёт обычный объект без реактивности. Для сохранения реактивности следует использовать reactive() или ref() для новых объектов.

import { reactive } from 'vue';

const original = reactive({ user: { name: 'Alice' } });
const copy = reactive(JSON.parse(JSON.stringify(original)));

copy.user.name = 'Bob'; // Не влияет на original и остаётся реактивным только в copy

Рекомендации по использованию

  • Использовать поверхностное отслеживание для больших объектов с редко изменяемыми вложенными свойствами.
  • Применять глубокое отслеживание только при необходимости отслеживать изменения в любом уровне вложенности.
  • Избегать глубоких реактивных объектов с огромной вложенностью, чтобы не перегружать систему наблюдателей.
  • Использовать ref для примитивов и объектов, когда нужно контролировать реактивность вручную.

Глубокое и поверхностное отслеживание — ключевые аспекты реактивности Vue, определяющие, какие изменения данных приводят к обновлению интерфейса. Понимание этих механизмов позволяет эффективно управлять состоянием приложений и оптимизировать производительность.