Вычисляемые свойства computed во Vue.js

05 марта 2026
Автор

Олег Марков

Введение

Вычисляемые свойства (computed) во Vue.js — это один из тех инструментов, которые сильно упрощают жизнь, если правильно ими пользоваться. Они позволяют описывать производные значения на основе состояния компонента и при этом не дублировать код в шаблоне или в методах.

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

Давайте разберемся, что такое computed, чем оно отличается от методов и наблюдателей (watch), как правильно его использовать и какие подводные камни чаще всего возникают у разработчиков.

Что такое вычисляемые свойства computed

Основная идея computed

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

Проще говоря:

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

Простейший пример

Давайте посмотрим на базовый пример на Vue 2:

// Здесь мы создаем новый экземпляр Vue
const vm = new Vue({
  el: '#app',
  data: {
    firstName: 'Иван',
    lastName: 'Иванов'
  },
  computed: {
    // Здесь мы объявляем вычисляемое свойство fullName
    fullName() {
      // Оно будет автоматически пересчитываться,
      // когда изменится firstName или lastName
      return this.firstName + ' ' + this.lastName
    }
  }
})

В шаблоне это выглядит так:

<div id="app">
  <!-- Здесь мы обращаемся к computed-свойству как к обычному полю -->
  <p>{{ fullName }}</p>
</div>

Обратите внимание: мы пишем {{ fullName }}, а не {{ fullName() }}. Это важно — вычисляемые свойства работают как геттеры, а не как методы.

Теперь, если вы сделаете:

// Здесь мы меняем исходные данные
vm.firstName = 'Петр'
// Vue автоматически пересчитает fullName

Содержимое {{ fullName }} в шаблоне обновится автоматически.

Пример на Vue 3 (Composition API)

В Vue 3 есть отдельная функция computed, но идея та же. Смотрите, как это выглядит:

import { ref, computed } from 'vue'

export default {
  setup() {
    // Создаем реактивные данные через ref
    const firstName = ref('Иван')
    const lastName = ref('Иванов')

    // Создаем вычисляемое свойство
    const fullName = computed(() => {
      // Используем .value, так как это ref
      return firstName.value + ' ' + lastName.value
    })

    // Возвращаем, чтобы использовать в шаблоне
    return {
      firstName,
      lastName,
      fullName
    }
  }
}

В шаблоне будет то же самое:

<p>{{ fullName }}</p>

Здесь Vue сам следит, что fullName зависит от firstName и lastName, и пересчитывает его только когда эти значения меняются.

Чем computed отличается от methods и watch

Computed vs methods

Частый вопрос: почему бы просто не использовать метод? Давайте разберемся на простом примере.

computed: {
  // Вычисляемое свойство
  fullNameComputed() {
    console.log('computed выполняется')
    return this.firstName + ' ' + this.lastName
  }
},
methods: {
  // Метод
  fullNameMethod() {
    console.log('method выполняется')
    return this.firstName + ' ' + this.lastName
  }
}

И шаблон:

<p>{{ fullNameComputed }}</p>
<p>{{ fullNameMethod() }}</p>
<p>{{ fullNameMethod() }}</p>

Что происходит:

  • fullNameComputed вычислится один раз и закэшируется, пока не изменится firstName или lastName;
  • fullNameMethod() выполнится каждый раз при любом обновлении компонента и каждый раз, когда он вызван в шаблоне.

То есть:

  • computed — про зависимые данные и кэширование;
  • methods — про действия (обработчики, события, логика без кэша).

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

Computed vs watch

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

Пример на watch:

data() {
  return {
    searchQuery: '',
    results: []
  }
},
watch: {
  // Здесь мы следим за изменением searchQuery
  searchQuery(newValue) {
    // Здесь мы вызываем функцию, которая делает запрос на сервер
    this.fetchResults(newValue)
  }
},
methods: {
  fetchResults(query) {
    // Здесь могла бы быть логика HTTP-запроса
    console.log('Запрашиваем результаты для', query)
  }
}

Здесь watch уместен, потому что:

  • нам нужен побочный эффект — запрос;
  • нам не нужно «виртуальное» значение для шаблона.

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

Кратко:

  • computed — для декларативных зависимых значений;
  • watch — для побочных эффектов при изменении данных;
  • methods — для действий, которые выполняются по событию и не кэшируются.

Кэширование и отслеживание зависимостей

Как работает кэширование вычисляемых свойств

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

  • если ни одна зависимость не изменилась — возвращается старое значение из кэша;
  • если хотя бы одна зависимость изменилась — функция вычисления запускается заново.

Давайте посмотрим на пример, где кэширование помогает:

computed: {
  heavyComputed() {
    // Это "тяжелая" функция с большим количеством вычислений
    console.log('Выполняем тяжелое вычисление...')
    let sum = 0
    // Здесь мы специально делаем много итераций
    for (let i = 0; i < 1000000; i++) {
      sum += i
    }
    return sum + this.extra
  }
},
data() {
  return {
    extra: 10,
    counter: 0
  }
},
methods: {
  increment() {
    // Изменяем только counter
    this.counter++
  }
}

В шаблоне:

<p>{{ heavyComputed }}</p>
<p>{{ counter }}</p>
<button @click="increment">Увеличить</button>

Как это работает:

  • при первом рендере heavyComputed выполнится и результат будет сохранен в кэше;
  • при клике на кнопку обновится только counter;
  • зависимости heavyComputed — это extra, а не counter, поэтому тяжелая функция не будет запускаться снова;
  • Vue возьмет закэшированное значение.

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

Как Vue понимает, что пересчитывать

Vue автоматически отслеживает, к каким реактивным данным вы обращаетесь внутри функции computed. Все такие обращения добавляются в список зависимостей. Если какое‑то из этих значений изменится, вычисляемое свойство помечается как «грязное», и при следующем доступе к нему будет выполнен пересчет.

То есть вам не нужно явно указывать зависимости, как, например, в React с useMemo — Vue делает это за вас.

Геттеры и сеттеры для computed

Вычисляемое свойство только с геттером

Чаще всего computed используется как только геттер, без возможности записи:

computed: {
  fullName() {
    return this.firstName + ' ' + this.lastName
  }
}

Если вы попытаетесь присвоить этому свойству значение:

this.fullName = 'Новая строка'

Ничего полезного не произойдет, потому что по умолчанию setter у computed нет.

Computed с геттером и сеттером

Иногда бывает нужно «обратное» преобразование: вы хотите, чтобы при установке значения в computed автоматически менялись исходные поля. Тогда вы можете объявить computed как объект с полями get и set.

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

data() {
  return {
    firstName: 'Иван',
    lastName: 'Иванов'
  }
},
computed: {
  fullName: {
    // Геттер вызывается, когда вы обращаетесь к this.fullName
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // Сеттер вызывается, когда вы присваиваете this.fullName = '...'
    set(value) {
      // Здесь мы разбиваем строку на части по пробелу
      const parts = value.split(' ')
      // Обновляем исходные данные
      this.firstName = parts[0] || ''
      this.lastName = parts[1] || ''
    }
  }
}

Теперь вы можете сделать:

// Здесь сработает setter полноты имени
this.fullName = 'Петр Петров'
// firstName станет 'Петр', lastName станет 'Петров'

В шаблоне:

<!-- Здесь мы двусторонне связываем input с computed через v-model -->
<input v-model="fullName">

Обратите внимание:

  • при вводе текста в поле ввода вызывается setter fullName, он обновляет firstName и lastName;
  • при изменении firstName или lastName Vue пересчитает значение fullName через getter, и это отразится в поле ввода.

Так вы получаете реактивное «виртуальное» поле, у которого есть и чтение, и запись.

Computed с get/set в Vue 3 (Composition API)

В Composition API вы можете задать геттер и сеттер через объект:

import { ref, computed } from 'vue'

export default {
  setup() {
    const firstName = ref('Иван')
    const lastName = ref('Иванов')

    const fullName = computed({
      // Геттер
      get() {
        return firstName.value + ' ' + lastName.value
      },
      // Сеттер
      set(value) {
        const parts = value.split(' ')
        firstName.value = parts[0] || ''
        lastName.value = parts[1] || ''
      }
    })

    return {
      firstName,
      lastName,
      fullName
    }
  }
}

Теперь в шаблоне можно использовать:

<input v-model="fullName">

Vue сам поймет, что это computed с геттером и сеттером.

Правильные сценарии использования computed

Когда использовать computed

Используйте вычисляемые свойства, когда:

  1. Значение логически является производным от других реактивных данных.
  2. Вам нужно использовать это значение в нескольких местах (в шаблоне или в логике).
  3. Вы хотите избежать дублирования кода.
  4. Вычисление может быть не самым дешевым по производительности, и кэширование имеет смысл.

Примеры:

  • форматирование даты или числа;
  • фильтрация и сортировка списков;
  • подсчет сумм, количества, средних значений;
  • объединение нескольких полей в одно (как в примере с fullName).

Когда лучше использовать методы

Предпочтительнее использовать methods, если:

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

Например:

methods: {
  // Здесь мы генерируем случайный идентификатор
  generateId() {
    return Math.random().toString(36).slice(2)
  }
}

Такую функцию нет смысла делать computed, потому что:

  • кэширование ломает идею «случайности»;
  • значение зависит не от данных, а от момента вызова.

Когда использовать watch

Watch полезен, когда:

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

Например:

watch: {
  // Отслеживаем изменение выбранной вкладки
  currentTab(newTab) {
    // Сохраняем выбор пользователя в localStorage
    // Это побочный эффект, а не просто вычисление значения
    localStorage.setItem('lastTab', newTab)
  }
}

Здесь computed не подходит, потому что сама суть — побочный эффект, а не новое «виртуальное» поле.

Примеры практического использования computed

Фильтрация списка

Давайте разберемся на примере типичной задачи: фильтрация списка элементов по строке поиска.

data() {
  return {
    search: '',
    items: [
      { id: 1, name: 'Яблоко' },
      { id: 2, name: 'Банан' },
      { id: 3, name: 'Апельсин' }
    ]
  }
},
computed: {
  // Вычисляем отфильтрованный список
  filteredItems() {
    // Приводим строку к нижнему регистру для удобства поиска
    const query = this.search.toLowerCase()

    // Фильтруем элементы по условию вхождения подстроки
    return this.items.filter(item =>
      item.name.toLowerCase().includes(query)
    )
  }
}

Шаблон:

<input v-model="search" placeholder="Поиск">
<ul>
  <!-- Здесь мы выводим только отфильтрованные элементы -->
  <li v-for="item in filteredItems" :key="item.id">
    {{ item.name }}
  </li>
</ul>

Что здесь важно:

  • filteredItems всегда «свежий» — он зависит от search и items;
  • при вводе в поле поиска список автоматически пересчитывается;
  • если список большой, кэширование помогает не пересчитывать его, когда меняется что‑то другое в компоненте.

Подсчет агрегированных значений

Представим корзину магазина. Покажу вам пример, как удобно посчитать итоговую сумму и количество товаров через computed.

data() {
  return {
    cart: [
      { id: 1, name: 'Товар A', price: 1000, quantity: 2 },
      { id: 2, name: 'Товар B', price: 500, quantity: 1 }
    ],
    discount: 0.1 // Скидка 10%
  }
},
computed: {
  // Общее количество товаров
  totalItems() {
    return this.cart.reduce((sum, item) => {
      // Складываем количество каждого товара
      return sum + item.quantity
    }, 0)
  },
  // Сумма без скидки
  subtotal() {
    return this.cart.reduce((sum, item) => {
      // Складываем цену * количество
      return sum + item.price * item.quantity
    }, 0)
  },
  // Итоговая сумма с учетом скидки
  total() {
    // Используем другое computed-свойство
    const discounted = this.subtotal * (1 - this.discount)
    // Округляем до двух знаков после запятой
    return Math.round(discounted * 100) / 100
  }
}

Шаблон:

<p>Товаров в корзине - {{ totalItems }}</p>
<p>Сумма без скидки - {{ subtotal }} ₽</p>
<p>Итого со скидкой - {{ total }} ₽</p>

Обратите внимание:

  • computed может зависеть от других computed (total зависит от subtotal);
  • при изменении количества или скидки все итоговые значения пересчитаются автоматически.

Форматирование данных для отображения

Иногда в data вы храните «сырые» значения, а в шаблоне нужно показывать их в удобочитаемом виде. Здесь computed очень кстати.

data() {
  return {
    price: 1234.567,
    createdAt: '2023-07-01T12:34:56Z'
  }
},
computed: {
  formattedPrice() {
    // Здесь мы форматируем число как валюту
    return this.price.toFixed(2) + ' ₽'
  },
  formattedDate() {
    // Здесь мы создаем объект даты из строки
    const date = new Date(this.createdAt)
    // Собираем простую строку ДД.ММ.ГГГГ
    const day = String(date.getDate()).padStart(2, '0')
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const year = date.getFullYear()
    return `${day}.${month}.${year}`
  }
}

Шаблон:

<p>Цена - {{ formattedPrice }}</p>
<p>Создано - {{ formattedDate }}</p>

Смотрите, здесь мы отделяем «данные» (price, createdAt) от «представления» (formattedPrice, formattedDate). Это делает код чище и удобнее для поддержки.

Computed в Options API и Composition API

Вариант с Options API (Vue 2 и Vue 3)

В Options API все вычисляемые свойства описываются в одноименном объекте computed в опциях компонента:

export default {
  data() {
    return {
      a: 1,
      b: 2
    }
  },
  computed: {
    sum() {
      return this.a + this.b
    }
  }
}

Плюсы:

  • код хорошо читается для небольших компонентов;
  • блок computed визуально отделен от методов и данных.

Минусы:

  • при больших компонентах логика может быть «размазана» по разным опциям (data, computed, methods и т.д.).

Вариант с Composition API (Vue 3)

В Composition API вы используете функцию computed внутри setup:

import { ref, computed } from 'vue'

export default {
  setup() {
    const a = ref(1)
    const b = ref(2)

    const sum = computed(() => {
      return a.value + b.value
    })

    return {
      a,
      b,
      sum
    }
  }
}

Плюсы:

  • можно группировать связанную логику рядом (данные, computed, watch, методы);
  • удобнее масштабировать большие компоненты;
  • проще выносить повторяемую логику в отдельные функции / композиционные хуки.

Особенность: с ref вам нужно использовать .value внутри computed. В шаблоне же sum и a ведут себя как обычные значения — Vue сам «разворачивает» .value.

Чего делать с computed не стоит

Не использовать побочные эффекты внутри computed

Вычисляемые свойства должны быть «чистыми» функциями — без побочных эффектов. То есть:

  • никакого ручного изменения других реактивных данных;
  • никаких HTTP-запросов;
  • никаких таймеров, логирования в консоль в реальной логике и т.п.

Неправильный пример:

computed: {
  userData() {
    // Плохо - здесь мы делаем запрос
    this.fetchUser() // Это метод, который меняет состояние
    return this.user
  }
}

Почему это опасно:

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

Вместо этого:

  • для запроса — используйте метод + вызов в mounted или по событию;
  • для реакции на изменение значения — используйте watch.

Не мутировать состояния в computed

Неправильный (и потенциально опасный) пример:

computed: {
  normalizedItems() {
    // Плохо - мы мутируем исходный массив items
    this.items.forEach(item => {
      item.normalizedName = item.name.toLowerCase()
    })
    return this.items
  }
}

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

Лучше сделать так:

computed: {
  normalizedItems() {
    // Хорошо - мы создаем новый массив и новый объект для каждого элемента
    return this.items.map(item => {
      return {
        ...item,
        normalizedName: item.name.toLowerCase()
      }
    })
  }
}

Здесь computed возвращает новое значение, не меняя исходные данные напрямую.

Не использовать computed там, где подходит простое поле data

Иногда разработчики делают computed просто ради факта, хотя это обычное состояние:

computed: {
  // Не нужно
  isVisible: {
    get() {
      return this._isVisible
    },
    set(value) {
      this._isVisible = value
    }
  }
},
data() {
  return {
    _isVisible: false
  }
}

Это усложнение без пользы. Если значение не является производным, его проще и понятнее держать в data:

data() {
  return {
    isVisible: false
  }
}

Оптимизация и производительность

Когда computed реально помогает по скорости

Особенно полезно использовать computed в таких ситуациях:

  • фильтрация или сортировка больших списков;
  • сложные математические вычисления;
  • преобразование данных, которые часто используются в шаблоне.

Например, если у вас таблица с сотнями строк и сложной логикой фильтрации, давайте вынесем ее в computed:

computed: {
  processedRows() {
    // Здесь мы последовательно применяем фильтрацию и сортировку
    let rows = this.rows

    if (this.search) {
      const query = this.search.toLowerCase()
      rows = rows.filter(row =>
        row.name.toLowerCase().includes(query)
      )
    }

    if (this.sortField) {
      rows = [...rows].sort((a, b) => {
        // Здесь мы сортируем по выбранному полю
        if (a[this.sortField] < b[this.sortField]) return -1
        if (a[this.sortField] > b[this.sortField]) return 1
        return 0
      })
    }

    return rows
  }
}

Vue выполнит эту функцию только тогда, когда изменятся rows, search или sortField, а не при каждом обновлении компонента.

Когда кэширование не дает выгоды

Если вычисление очень простое и дешевое (например, суммирование двух чисел), кэширование дает минимальную выгоду, но все равно улучшает читаемость кода. Главное — не использовать computed для того, что не зависит от реактивных данных вообще.

Нецелесообразно, например, такое:

computed: {
  currentTimestamp() {
    // Здесь мы просто возвращаем текущее время
    return Date.now()
  }
}

Значение не зависит от состояния и становится устаревшим уже через миллисекунду, а кэширование только вредит. Для этого больше подходит метод или явное обновление значения в data через таймер.

Частые ошибки при работе с computed

Ошибка 1. Попытка передать аргументы в computed

Иногда разработчики пытаются сделать так:

computed: {
  getUserById(id) {
    // Так нельзя - computed не принимает аргументы
    return this.users.find(user => user.id === id)
  }
}

Computed не принимает аргументы. Это не метод, а свойство.

Как правильно:

  • если нужен поиск по параметру — используйте метод;
  • если нужно часто работать с конкретным параметром — сделайте отдельное computed или используйте computed, который возвращает функцию.

Пример с методом:

methods: {
  getUserById(id) {
    // Здесь мы ищем пользователя по id
    return this.users.find(user => user.id === id)
  }
}

Пример с computed, возвращающим функцию:

computed: {
  userById() {
    // Здесь мы возвращаем функцию, которая может принимать id
    return id => this.users.find(user => user.id === id)
  }
}

В шаблоне:

<p>{{ userById(10).name }}</p>

Ошибка 2. Отсутствие return в computed

Иногда забывают вернуть значение:

computed: {
  fullName() {
    // Здесь нет return
    this.firstName + ' ' + this.lastName
  }
}

Результат: в шаблоне fullName будет undefined. Всегда проверяйте, что в computed есть оператор return.

Ошибка 3. Использование async/await в computed

Vue поддерживает асинхронные функции в computed, но на практике это приводит к путанице. Например:

computed: {
  async userData() {
    // Здесь мы делаем асинхронный запрос
    const response = await fetch('/api/user')
    return await response.json()
  }
}

Что пойдет не так:

  • computed вернет Promise, а не готовые данные;
  • шаблон не умеет «дождаться» результата сам по себе;
  • придется вручную разворачивать Promise и писать дополнительную логику.

Чаще всего лучше:

  • делать запросы в хуках (mounted, onMounted) или методах;
  • сохранять результат в data / ref;
  • использовать computed только для производных значений от уже загруженных данных.

Ошибка 4. Опора на то, что computed будет вызываться строго в определенный момент

Не стоит полагаться на порядок и частоту вызовов computed. Vue сам решает, когда и сколько раз вызывать вычисляемые свойства в зависимости от обновлений. Ваша задача — сделать функцию чистой и детерминированной: одинаковые входные данные — одинаковый результат, без побочных эффектов.


Заключение

Вычисляемые свойства (computed) во Vue.js — это удобный способ описывать производные значения, которые автоматически следят за своими зависимостями и кэшируются. Они помогают:

  • отделять «данные» от их представления;
  • избегать дублирования кода в шаблонах и методах;
  • оптимизировать тяжелые вычисления за счет кэширования;
  • делать код компонентов более чистым и предсказуемым.

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

  • computed ведет себя как свойство, а не как функция;
  • результат вычисляемого свойства кэшируется до изменения зависимостей;
  • для побочных эффектов лучше использовать watch или методы;
  • computed-функции должны быть «чистыми» — без асинхронных запросов и без мутации стороннего состояния;
  • при необходимости можно использовать геттер и сеттер и даже двустороннее связывание через v-model.

Если вы будете воспринимать computed как декларативное описание того, «что можно получить из текущего состояния компонента», а не как «еще один способ написать функцию», то это станет мощным инструментом для упрощения логики и улучшения структуры кода.


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

Как сбросить кэш вычисляемого свойства вручную

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

Пример:

data() {
  return {
    forceUpdateKey: 0,
    value: 1
  }
},
computed: {
  computedValue() {
    // Добавляем искусственную зависимость
    void this.forceUpdateKey
    return this.value * 2
  }
},
methods: {
  recalc() {
    // Увеличиваем счетчик, чтобы заставить computed пересчитаться
    this.forceUpdateKey++
  }
}

Почему мое computed не обновляется при изменении объекта или массива

Часто проблема в том, что объект или массив мутируются не реактивно (в Vue 2) или вы не создаете новое значение. Решение:

  • в Vue 2 используйте методы Vue.set или замену массива/объекта целиком;
  • в Vue 3 старайтесь создавать новые объекты и массивы при изменении структуры.
// Вместо прямого присваивания свойства
this.obj.newProp = 1
// Используйте
this.obj = { ...this.obj, newProp: 1 }

Можно ли использовать computed внутри другого computed в Composition API

Да, можно. Computed в Composition API — это тоже реактивные источники. Внутри одного computed вы спокойно обращаетесь к другому:

const a = ref(1)
const doubled = computed(() => a.value * 2)
const tripledOfDoubled = computed(() => doubled.value * 3)

Vue сам выстроит цепочку зависимостей и пересчитает значения в нужном порядке.

Как типизировать computed в TypeScript с Composition API

Функция computed в Vue 3 умеет выводить тип автоматически, но при необходимости вы можете указать его явно:

const a = ref<number>(1)

// Здесь мы явно задаем тип для computed
const doubled = computed<number>(() => a.value * 2)

Для computed с get/set:

const fullName = computed<string>({
  get() {
    return firstName.value + ' ' + lastName.value
  },
  set(value: string) {
    // ...
  }
})

Почему computed с async/await возвращает Promise в шаблоне

Асинхронная функция всегда возвращает Promise. Computed не «ждет» этот Promise — он просто кэширует его как значение. В шаблоне вы увидите или [object Promise], или вообще ничего полезного. Решение — не использовать async в computed, а:

  1. сделать запрос в методе или хуке;
  2. сохранить результат в реактивное поле;
  3. использовать computed только для синхронных преобразований уже загруженных данных.
Стрелочка влевоКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSСтрелочка вправо

Постройте личный план изучения 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
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Работа с пользовательскими интерфейсами и 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
Функция 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 проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на 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 создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования 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 ₽
Подробнее

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