Реактивные значения reactive values в современных фреймворках

28 января 2026
Автор

Олег Марков

Введение

Реактивные значения (reactive values) лежат в основе большинства современных frontend‑фреймворков и многих библиотек для управления состоянием. Когда вы используете ref во Vue, signal в Angular, writable в Svelte, BehaviorSubject в RxJS или atom в jotai/ Recoil — вы фактически работаете с реактивными значениями, просто под разными именами.

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

В этой статье я покажу, что такое реактивные значения на уровне идей, как они реализуются под капотом и как с ними работать в разных сценариях. Мы не будем привязываться строго к одному фреймворку, но для наглядности возьмем примеры на базе типичного API с концепциями signal/ref и computed/derived. Так вы сможете перенести понимание в любой стек.


Базовая идея реактивных значений

Что такое реактивное значение

Реактивное значение — это обертка над обычным значением, которая:

  1. Позволяет безопасно читать и изменять это значение.
  2. Умеет уведомлять всех «подписчиков» об изменении.
  3. Может автоматически запускать связанные вычисления или перерисовку интерфейса.

Давайте посмотрим на минималистичную реализацию на чистом JavaScript, чтобы вы увидели суть без магии фреймворков.

Простейшая реализация reactive value

Смотрите, я покажу вам, как можно реализовать простейшее реактивное значение руками:

// Простейшее реактивное значение
function createReactiveValue(initial) {
  let value = initial               // Текущее значение
  const listeners = new Set()       // Набор подписчиков

  return {
    get() {
      // Вернуть текущее значение
      return value
    },
    set(newValue) {
      // Если значение не изменилось - ничего не делаем
      if (Object.is(value, newValue)) return

      value = newValue
      // Оповещаем всех подписчиков об изменении
      listeners.forEach((fn) => fn(value))
    },
    subscribe(fn) {
      // Добавляем функцию-подписчика
      listeners.add(fn)
      // Возвращаем функцию отписки
      return () => listeners.delete(fn)
    }
  }
}

Теперь давайте разберемся на примере, как это использовать:

const count = createReactiveValue(0)

// Подписываемся на изменение
const unsubscribe = count.subscribe((newValue) => {
  console.log('Новое значение счетчика:', newValue)
})

// Меняем значение
count.set(1) // В консоль выведется - Новое значение счетчика 1
count.set(2) // В консоль выведется - Новое значение счетчика 2

// Отписываемся
unsubscribe()

count.set(3) // Никаких логов - подписчик отписан

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

Большинство популярных фреймворков делают примерно то же самое, только дополняют это:

  • отслеживанием зависимостей,
  • мемоизацией вычислений,
  • интеграцией с рендерингом,
  • оптимизацией производительности.

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

API чтения и записи

В разных библиотеках API может выглядеть по-разному:

  • Vue: const count = ref(0) — чтение count.value, запись count.value = 1
  • Angular (signals): const count = signal(0) — чтение count(), запись count.set(1)
  • SolidJS: const [count, setCount] = createSignal(0) — чтение count(), запись setCount(1)
  • Svelte: const count = writable(0) — чтение через подписку или $count в шаблоне, запись count.set(1)
  • RxJS: const count$ = new BehaviorSubject(0) — чтение count$.value, запись count$.next(1)

Но концептуально это одинаково: есть механизм get и set.

Чтобы было проще, давайте использовать условный API формата:

  • signal(initialValue) — создать реактивное значение
  • value() — прочитать
  • value.set(newValue) — записать
  • value.subscribe(listener) — подписаться

Это не конкретный фреймворк, а обобщенная модель.

Вот пример:

// Условная реализация, похожая на Angular signals
function signal(initial) {
  let value = initial
  const listeners = new Set()

  function read() {
    return value
  }

  read.set = (next) => {
    if (Object.is(value, next)) return
    value = next
    listeners.forEach((fn) => fn(value))
  }

  read.subscribe = (fn) => {
    listeners.add(fn)
    // Сразу вызываем подписчика с текущим значением
    fn(value)
    return () => listeners.delete(fn)
  }

  return read
}

Теперь вы увидите, как это выглядит в коде:

const count = signal(0)

// Чтение значения
console.log(count()) // 0

// Подписка
const stop = count.subscribe((v) => {
  console.log('count изменился на', v)
})

// Запись
count.set(1) // В консоли - count изменился на 1
count.set(2) // В консоли - count изменился на 2

stop()       // Отписываемся

Логика вокруг записи

Обратите внимание на важные детали при записи:

  1. Часто проверяется, изменилось ли значение реально (Object.is(old, next)).
  2. Подписчики вызываются только при реальном изменении — так экономятся лишние перерисовки.
  3. Подписчики вызываются синхронно или асинхронно — это сильно влияет на поведение системы.

Многие реактивные системы (Vue, Angular signals, Solid) вызывают подписчиков синхронно, но могут планировать обновление DOM асинхронно (батчинг). RxJS может давать гибкость через планировщики.


Вычисляемые реактивные значения (computed / derived)

Зачем нужны вычисляемые значения

Обычно вам мало просто хранить какие-то данные — вам нужно вычислять Derived Data: фильтрованные списки, форматированные строки, суммы, агрегаты.

Если вы будете считать все руками в обработчиках, логика быстро расползется. Реактивные библиотеки решают это через computed / derived значения.

Идея: у вас есть реактивные значения a и b, и вы хотите реактивное значение sum, которое всегда равно a + b.

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

  • зависимость sum от a и b,
  • функцию вычисления sum.

Фреймворк сам отслеживает зависимости и пересчитывает sum, когда нужно.

Простая реализация computed

Покажу вам, как это реализовано на практике, на основе нашей функции signal:

function computed(getter) {
  const value = signal(undefined)  // Внутреннее реактивное значение
  let cleanup = null               // Функция для отписки от зависимостей (упрощенно)

  function recompute() {
    const newValue = getter()
    value.set(newValue)
  }

  // Здесь мы просто один раз считаем значение.
  // В реальных реализациях нужно отслеживать, от каких signal зависит getter.
  recompute()

  // Возвращаем только функцию чтения и подписку
  const read = () => value()
  read.subscribe = value.subscribe

  return read
}

В реальных библиотеках computed умеют:

  • автоматически регистрировать зависимости,
  • пересчитываться только при изменении зависимостей,
  • кэшировать результат до следующего изменения.

Давайте посмотрим, как это может выглядеть в более живом примере:

const firstName = signal('Иван')
const lastName = signal('Петров')

// Вычисляемое реактивное значение
const fullName = computed(() => {
  // Здесь мы используем значения сигналов
  return firstName() + ' ' + lastName()
})

// Подписываемся на изменение fullName
fullName.subscribe((v) => {
  console.log('Полное имя:', v)
})

// Меняем исходные части
firstName.set('Сергей')  // В идеале - пересчитается fullName
lastName.set('Иванов')   // fullName снова пересчитается

Фреймворк сам понимает, что fullName зависит от firstName и lastName, и пересчитывает результат только тогда, когда это действительно нужно.


Автоматическое отслеживание зависимостей

Как система понимает, от чего зависит вычисление

Самая «магическая» часть реактивных систем — это трекинг зависимостей. Но если посмотреть внимательнее, идея довольно понятна.

Чаще всего применяют такой прием:

  1. Есть глобальная переменная activeEffect, в которой хранится текущая реактивная «реакция» (эффект, computed и т.п.).
  2. Когда эффект выполняется, мы устанавливаем activeEffect на него.
  3. При чтении любого сигналa (reactive value) смотрим: если activeEffect не пустой — значит, этот сигнал является зависимостью текущего эффекта.
  4. При изменении сигнала вызываем все эффекты, которые на него подписаны.

Давайте разберемся на примере упрощенной реализации эффектов.

Реализация эффекта (effect / autorun)

Эффект — это функция, которая автоматически запускается, когда меняются ее реактивные зависимости.

let activeEffect = null

function effect(fn) {
  const runner = () => {
    activeEffect = runner    // Устанавливаем текущий активный эффект
    fn()                     // Выполняем пользовательский код
    activeEffect = null      // Сбрасываем активный эффект
  }

  runner.deps = new Set()    // Множество зависимостей

  runner()                   // Выполняем сразу один раз при создании
  return runner
}

Теперь чуть изменим наш signal, чтобы он регистрировал эффекты:

function signal(initial) {
  let value = initial
  const listeners = new Set()
  const dependents = new Set() // Эффекты, зависящие от сигнала

  function read() {
    // Если есть активный эффект - добавляем его в зависимости
    if (activeEffect) {
      dependents.add(activeEffect)
      activeEffect.deps.add(dependents)
    }
    return value
  }

  read.set = (next) => {
    if (Object.is(value, next)) return
    value = next
    // Оповещаем "слушателей" (прямых подписчиков)
    listeners.forEach((fn) => fn(value))
    // Запускаем все эффекты, которые зависят от этого сигнала
    dependents.forEach((eff) => eff())
  }

  read.subscribe = (fn) => {
    listeners.add(fn)
    fn(value)
    return () => listeners.delete(fn)
  }

  return read
}

Теперь давайте посмотрим, что происходит в следующем примере:

const count = signal(0)
const double = signal(0)

effect(() => {
  // Этот эффект зависит от count
  console.log('Текущее значение count:', count())
})

effect(() => {
  // Этот эффект зависит и от count и от double
  console.log('Сумма count + double:', count() + double())
})

// Изменяем значения
count.set(1)  // Перезапустятся оба эффекта
double.set(10) // Перезапустится только второй эффект

Здесь важно понять: система автоматически запоминает, что второй эффект вызвал count() и double(), поэтому при изменении этих сигналов эффект переисполнится.


Реактивные значения и UI: связь с рендерингом

Привязка к DOM

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

Простой пример: вы хотите, чтобы содержимое div всегда соответствовало реактивному значению count.

Можно сделать что-то вроде (упрощенно, как в небольших фреймворках):

const count = signal(0)

const div = document.createElement('div')
document.body.appendChild(div)

// Эффект, который связывает DOM и реактивное значение
effect(() => {
  // Каждый раз, когда count меняется, этот код выполняется заново
  div.textContent = 'Счетчик - ' + count()
})

// Где-то в коде вы меняете значение
setInterval(() => {
  count.set(count() + 1)   // Интерфейс автоматически обновится
}, 1000)

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

Реальные фреймворки поверх этого слоя строят:

  • виртуальный DOM (React, Vue),
  • fine-grained обновления (Solid, Svelte, Angular signals),
  • шаблоны и JSX.

Но фундамент — тот же: изменение реактивного значения триггерит пересчет части UI.

Батчинг и микротаски

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

  • Изменения собираются в очередь.
  • В конце микротаски или кадра (requestAnimationFrame) фреймворк пересчитывает зависимости и обновляет DOM.

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


Работа с массивами и объектами

Проблема «глубокой» реактивности

До сих пор мы рассматривали сигнал как обертку над примитивом. Но в реальных приложениях вы часто храните в состоянии:

  • объекты (пользователь, настройки),
  • массивы (списки элементов),
  • вложенные структуры.

Основной вопрос: как система понимает, что user.name изменился? Есть два подхода:

  1. Глубокая (deep) реактивность — каждый вложенный путь отслеживается.
  2. Поверхностная (shallow) — значение объекта/массива считается единым целым.

Во Vue, например, используется прокси над объектами, которые отслеживают доступ к полям. В signals-подходе чаще применяют «иммутабельный» стиль: любое изменение структуры создает новый объект/массив.

Реактивный объект через signal

Давайте посмотрим простой вариант: мы храним объект в одном сигнале и меняем его иммутабельно.

const user = signal({
  name: 'Иван',
  age: 30
})

effect(() => {
  // Эффект зависит от всего объекта user
  const u = user()
  console.log('Пользователь:', u.name, 'Возраст:', u.age)
})

// Меняем только имя - но меняем целиком объект
user.set({
  ...user(),
  name: 'Петр'
})

Здесь важно: user.set вызывается с новым объектом, и все подписчики, использующие user(), будут уведомлены.

Локальная реактивность для полей

Иногда удобнее разбить объект на отдельные реактивные значения:

const userName = signal('Иван')
const userAge = signal(30)

effect(() => {
  console.log('Имя пользователя:', userName())
})

effect(() => {
  console.log('Возраст пользователя:', userAge())
})

// Меняем только имя - не трогаем возраст
userName.set('Петр')

Так вы более точно контролируете, какие части интерфейса обновляются при каких изменениях.

Работа с массивами

С массивами ситуация похожа: вы либо обновляете массив иммутабельно, либо используете специальные методы, которые внутри делают новый массив.

Давайте разберемся на примере списка задач:

const todos = signal([])

// Эффект, который реагирует на изменение списка
effect(() => {
  console.log('Список задач:', todos())
})

// Добавление задачи
function addTodo(text) {
  const current = todos()
  todos.set([
    ...current,             // Копируем старые задачи
    { id: Date.now(), text, done: false }
  ])
}

// Изменение флага done для задачи
function toggleTodo(id) {
  const current = todos()
  todos.set(
    current.map(todo =>
      todo.id === id
        ? { ...todo, done: !todo.done } // Создаем новый объект задачи
        : todo
    )
  )
}

Здесь я размещаю пример с иммутабельными обновлениями: каждый раз создается новый массив, а не изменяется старый. Это упрощает трекинг изменений.


Потоки, асинхронность и реактивные значения

Реактивные значения и async/await

Один из распространенных кейсов — загрузка данных по сети и сохранение их в реактивное значение, чтобы интерфейс автоматически обновился.

Давайте посмотрим небольшой пример:

const isLoading = signal(false)
const error = signal(null)
const data = signal(null)

async function loadData() {
  isLoading.set(true)
  error.set(null)

  try {
    // Здесь мы выполняем запрос
    const res = await fetch('/api/items')
    if (!res.ok) {
      throw new Error('Ошибка загрузки')
    }
    const json = await res.json()
    data.set(json)      // Сохраняем данные в сигнал
  } catch (e) {
    error.set(e.message || 'Неизвестная ошибка')
  } finally {
    isLoading.set(false)
  }
}

effect(() => {
  // Реагируем на смену состояния загрузки
  console.log('isLoading:', isLoading(), 'error:', error())
})

effect(() => {
  // Реагируем на обновление данных
  console.log('Данные:', data())
})

Как видите, этот код выполняет типичный асинхронный сценарий: при изменении isLoading, error и data связанный интерфейс или эффекты автоматически обновляются.

Реактивные значения vs потоковые библиотеки (RxJS)

Реактивные значения (signals, ref и т.п.) — это, как правило, «последнее известное значение», к которому вы можете обратиться в любой момент.

В RxJS и других потоковых библиотеках:

  • есть подписка на последовательность значений во времени,
  • часто нет прямой синхронной функции для чтения последнего значения (кроме специальных типов вроде BehaviorSubject),
  • много операторов для трансформаций (map, filter, switchMap и т.д.).

Реактивные значения ближе к «состоянию», а RxJS ближе к «потоку событий». Многие системы совмещают оба подхода: вы создаете поток, а затем «материализуете» его в реактивное значение.


Производительность и оптимизация реактивных значений

Зачем вообще думать о производительности

Реактивные системы удобны, но если бездумно создавать эффекты и зависимости, можно получить:

  • лишние пересчеты,
  • каскадные обновления,
  • сложные для отладки циклы.

Поэтому полезно понимать несколько базовых паттернов оптимизации.

Мемоизация computed значений

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

Ваша задача как разработчика — стараться выносить дорогие расчеты в computed, а не в эффекты или прямо в рендер.

Например:

const items = signal([/* ... большой массив ... */])

// Плохой вариант - фильтрация внутри эффекта каждый раз
effect(() => {
  const expensive = items().filter(/* ...сложный фильтр... */)
  console.log('Результат:', expensive)
})

// Лучше - выделить это в computed
const filteredItems = computed(() => {
  return items().filter(/* ...сложный фильтр... */)
})

effect(() => {
  console.log('Результат:', filteredItems())
})

Второй вариант позволяет фреймворку контролировать частоту пересчета и не дублировать работу.

Разбиение состояния

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

Например, вместо:

const state = signal({
  user: {...},
  todos: [...],
  settings: {...}
})

Можно сделать:

const user = signal({...})
const todos = signal([...])
const settings = signal({...})

Так эффекты, зависящие только от части состояния, не будут пересчитываться лишний раз.


Ошибки и типичные проблемы при работе с reactive values

Потеря реактивности из-за деструктуризации

Одна из частых ошибок — деструктуризация реактивного значения, когда вы забываете, что работаете не с обычным объектом, а с оберткой.

Например, во Vue:

const state = reactive({ count: 0 })
const { count } = state // Потеря реактивности для count

Или с сигналами:

const user = signal({ name: 'Иван', age: 30 })
const u = user()
// Дальше работа идет с u.name - это уже НЕ реактивное значение

Чтобы не терять реактивность, важно:

  • либо использовать API фреймворка для извлечения полей (например, toRef, store.select и т.п.),
  • либо не копировать значение без необходимости.

Создание циклических эффектов

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

Посмотрите на такой код:

const count = signal(0)

effect(() => {
  const value = count()
  if (value < 10) {
    // Ошибка - эффект сам изменяет зависимость
    count.set(value + 1)
  }
})

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

Чтобы избежать подобного:

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

Изменение массивов и объектов «по месту»

В иммутабельных подходах (React, многие signal-системы) нужно избегать мутаций по месту:

const list = signal([])

const arr = list()
arr.push(1)      // Мутация по месту
list.set(arr)    // Не всегда будет считаться «изменением»

Лучше всегда создавать новые массивы и объекты:

list.set([...list(), 1])

Примеры использования reactive values в разных контекстах

Пример 1: Счетчик с несколькими представлениями

Давайте рассмотрим простой, но показательный пример: у нас есть одно реактивное значение count, и мы хотим:

  • показывать его «сырое» значение,
  • выводить его в виде строки,
  • хранить его умноженным на 2.
const count = signal(0)

// Вычисляемое значение как строка
const countLabel = computed(() => {
  return 'Текущее значение счетчика - ' + count()
})

// Вычисляемое значение double
const doubleCount = computed(() => {
  return count() * 2
})

// Эффект для "логирования"
effect(() => {
  console.log(countLabel())
})

effect(() => {
  console.log('Удвоенное значение:', doubleCount())
})

// Меняем одно исходное значение, а все представления пересчитываются автоматически
count.set(5)
count.set(10)

Здесь мы видим, что одно реактивное значение может порождать цепочку производных значений, и все вместе образуют «дерево вычислений».

Пример 2: Форма с валидацией

Теперь давайте посмотрим, что происходит в более жизненном примере — форме входа с валидацией.

const email = signal('')
const password = signal('')

// Простейшая валидация email
const isEmailValid = computed(() => {
  const value = email()
  return value.includes('@') && value.includes('.')
})

// Валидация пароля
const isPasswordValid = computed(() => {
  return password().length >= 6
})

// Можно ли отправлять форму
const canSubmit = computed(() => {
  return isEmailValid() && isPasswordValid()
})

// Эффект для отладки
effect(() => {
  console.log('email valid:', isEmailValid(), 'password valid:', isPasswordValid())
})

effect(() => {
  console.log('Кнопка "Отправить" доступна:', canSubmit())
})

// Дальше где-то в UI вы связываете поля ввода с сигналами
function onEmailInput(value) {
  email.set(value)
}

function onPasswordInput(value) {
  password.set(value)
}

Теперь при каждом вводе в поля:

  • обновляются сигналы email и password,
  • пересчитываются isEmailValid и isPasswordValid,
  • затем canSubmit,
  • UI автоматически обновляет подсветку ошибок и состояние кнопки.

Заключение

Реактивные значения — это основа большинства современных решений для управления состоянием и построения интерфейсов. Внутри это всего лишь обертка над значением с возможностью подписки и автоматическим обновлением зависимых вычислений.

Ключевые идеи, которые важно удерживать:

  • Любое реактивное значение всегда состоит из get (чтение) и set (запись).
  • Под капотом почти всегда есть механизм эффекта (effect, autorun), который следит за зависимостями.
  • Вычисляемые значения (computed, derived) помогают формировать производные данные и не дублировать логику.
  • При работе с объектами и массивами проще и безопаснее использовать иммутабельный подход.
  • На базе реактивных значений довольно легко строится автоматическая синхронизация с UI.

Поняв концепцию реактивных значений, вы сможете увереннее работать с любым фреймворком, где есть signals, refs, stores, atoms и прочие похожие сущности — все они опираются на одни и те же принципы.


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

Вопрос 1. Как правильно «дебаунсить» или «троттлить» реакции на изменение реактивного значения

Иногда реактивное значение меняется слишком часто, и вам нужно ограничить частоту реакции (например, при вводе в поле поиска).

Мини-инструкция:

  1. Не изменяйте сам сигнал, а оборачивайте реакцию (effect или подписку).
  2. Внутри эффекта вызывайте вашу функцию не напрямую, а через debounce/throttle.

Пример:

const query = signal('')

// Обычный debounce
function debounce(fn, delay) {
  let timer = null
  return (...args) => {
    clearTimeout(timer)
    timer = setTimeout(() => fn(...args), delay)
  }
}

const search = debounce((q) => {
  // Здесь запрос на сервер
  console.log('Поиск по:', q)
}, 300)

effect(() => {
  search(query()) // Дебаунс применяется к реакции, а не к сигналу
})

Вопрос 2. Как отписываться от эффектов при уничтожении компонента

Если фреймворк не управляет эффектами сам, вам нужно вручную вызывать очистку.

Мини-инструкция:

  1. Модифицируйте effect, чтобы он возвращал функцию stop.
  2. При уничтожении компонента вызывайте ее.

Пример:

function effect(fn) {
  let active = true
  const runner = () => {
    if (!active) return
    activeEffect = runner
    fn()
    activeEffect = null
  }
  runner()
  return () => {
    active = false
  }
}

const stop = effect(() => {
  console.log('Работаю пока компонент жив')
})

// При уничтожении
stop()

Вопрос 3. Как безопасно работать с асинхронными запросами, чтобы старый ответ не перезаписал новый

Типичная проблема — новый запрос выполнен, но старый, завершившийся позже, «перебивает» данные.

Мини-инструкция:

  1. Храните «номер версии» или токен запроса в реактивном значении.
  2. Перед записью результата сравнивайте, актуален ли запрос.

Пример:

const data = signal(null)
const requestId = signal(0)

async function load() {
  const id = requestId() + 1
  requestId.set(id)

  const res = await fetch('/api/items')
  const json = await res.json()

  if (requestId() === id) {
    data.set(json) // Обновляем только если это самый свежий запрос
  }
}

Вопрос 4. Как объединять несколько реактивных значений в одно

Иногда нужно объединить несколько сигналов в «store».

Мини-инструкция:

  1. Создайте объект с полями-сигналами.
  2. Добавьте вспомогательные computed для комбинаций.

Пример:

const store = {
  firstName: signal('Иван'),
  lastName: signal('Петров'),
  fullName: null
}

store.fullName = computed(() => {
  return store.firstName() + ' ' + store.lastName()
})

Вопрос 5. Как тестировать код, использующий reactive values

Мини-инструкция:

  1. В юнит-тестах создавайте реальные сигналы.
  2. Явно вызывайте set и проверяйте, что эффекты/вычисления ведут себя как ожидается.
  3. Если эффекты автоматически запускаются, можно обернуть их в тестируемые функции.

Пример:

const count = signal(0)
let lastValue = null

effect(() => {
  lastValue = count() * 2
})

count.set(2)
console.assert(lastValue === 4)
Стрелочка влевоХуки жизненного цикла в Vue 3 Composition API - полный разбор с примерамиКомпозаблы composables во Vue 3Стрелочка вправо

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

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

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

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

Все гайды по Vue

Интеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackРуководство по валидации форм во Vue.jsИнструкция по установке и компонентам 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
Vuex - полное руководство по управлению состоянием во Vue приложенияхРеактивные ссылки ref - полный разбор для разработчиковРеактивные объекты reactive-objects - подробное руководство с примерамиРеактивные переменные - концепция reactive и практические примерыМеханизм Provide Inject - как он работает и когда применятьPinia современный менеджер состояния для VueЛокальное состояние local state в веб разработкеГлобальное состояние в приложениях - global state
Обзор и использование утилит 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
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueОрганизация и структура исходных файлов в проектах VueРабота с пользовательскими интерфейсами и UI библиотеками во 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
Функция append в Go GolangОтображение компонента mounted - практическое руководствоХуки жизненного цикла компонентов - полное руководство для разработчиковУничтожение компонента destroyed - как правильно очищать ресурсы и подпискиИнициализация данных в состоянии created - как и когда подготавливать данные в приложенииОбновление компонента beforeUpdate во VueМонтирование компонента - хук beforeMount в VueРазрушение компонента во Vue - beforeDestroy и beforeUnmountСоздание экземпляра beforeCreate - полный разбор жизненного цикла
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыГайд по импорту и регистрации компонентов на VueПримеры использования JSX во VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Слоты компонента - концепция и практическое использованиеРегистрация компонентов component-registration в приложениях с внедрением зависимостейProps компонента в React - полный разбор с примерамиФункциональные компоненты в React - функциональный подход к построению интерфейсовСобытия компонента - events в современных интерфейсахДинамические компоненты - dynamic-componentsСоздание компонента component - практическое руководствоАсинхронные компоненты async-components - практическое руководство
Наблюдатели watchers - от паттерна до практических реализацийУправление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsШаблоны Vue templates - практическое руководство для разработчиковИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueРеактивность Vue reactivity - как это работает под капотом и как этим пользоватьсяПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueОпции компонента в Go - паттерн component-optionsРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsРабота с динамическими компонентами и данными в VueКомпоненты Vue создание передача данных события и emit3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreВычисляемые свойства computed во Vue.jsСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueОсновы Vue - vue-basics для уверенного стартаИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueТелепортация - архитектура и реализация в серверных приложенияхРабота с teleport для управления DOM во VueSuspense в React - управление асинхронными данными и ленивой загрузкойПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиПлагины Vue vue-plugins - полное практическое руководствоРуководство по nextTick для работы с DOMМиксины - mixins в современном программированииJSX в Vue с использованием плагина vue-jsxСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьКастомные элементы - Custom Elements в современном JavaScriptИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

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

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

Vue 3 и Pinia

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

TypeScript с нуля

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

Next.js - с нуля

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

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