\n```\n\n### Решение с Computed\n\n#### Vue 3 (Composition API)\n\n```javascript\n\n\n\n```\n\n#### Vue 2 (Options API)\n\n```javascript\n\n\n\n```\n\n### Ключевые преимущества\n\n#### 1. Кеширование (Memoization)\n\n```javascript\nconst expensiveComputation = computed(() => {\n // Эта функция вызывается только если dependencies изменились!\n console.log('Дорогостоящий расчет...');\n \n let sum = 0;\n for (let i = 0; i < 1000000; i++) {\n sum += i; // Тяжелый расчет\n }\n return sum;\n});\n\n// Выполнение:\n// 1. expensiveComputation.value → логирует, вычисляет\n// 2. expensiveComputation.value → логирует НЕ вычисляет, возвращает кеш\n// 3. expensiveComputation.value → логирует НЕ вычисляет, возвращает кеш\n// Логируется только один раз!\n```\n\n#### 2. Чистота кода\n\n```javascript\n// ПЛОХО - inline логика в template\n
Verified
\n{{ user && user.profile && user.profile.name }}\n\n// ХОРОШО - используем computed\nconst isVerified = computed(() => user.value?.profile?.verified ?? false);\nconst userName = computed(() => user.value?.profile?.name ?? 'Unknown');\n\n
Verified
\n{{ userName }}\n```\n\n#### 3. Реактивность\n\n```javascript\nconst price = ref(100);\nconst quantity = ref(5);\nconst taxRate = ref(0.1);\n\nconst total = computed(() => {\n // Автоматически пересчитывается при изменении price, quantity или taxRate\n return price.value * quantity.value;\n});\n\nconst totalWithTax = computed(() => {\n // Зависит от total, которая зависит от других переменных\n return total.value * (1 + taxRate.value);\n});\n\n// При изменении price:\nprice.value = 200; // total автоматически пересчитается\n // totalWithTax автоматически пересчитается\n```\n\n#### 4. Фильтрация и сортировка списков\n\n```javascript\nconst items = ref([ { name: 'Apple', price: 100 },\n { name: 'Banana', price: 50 },\n { name: 'Cherry', price: 80 }\n]);\n\nconst searchQuery = ref('');\nconst sortBy = ref('price'); // 'name' или 'price'\n\n// Фильтруем и сортируем\nconst filteredItems = computed(() => {\n return items.value\n .filter(item => item.name.includes(searchQuery.value))\n .sort((a, b) => {\n if (sortBy.value === 'name') return a.name.localeCompare(b.name);\n return a.price - b.price;\n });\n});\n\n// Template\n
\n \n \n \n
\n```\n\n### Computed vs Methods\n\n```javascript\n// COMPUTED - кешируется\nconst fullName = computed(() => {\n console.log('computed triggered');\n return firstName.value + ' ' + lastName.value;\n});\n\n// METHOD - вызывается каждый раз\nconst getFullName = () => {\n console.log('method triggered');\n return firstName.value + ' ' + lastName.value;\n};\n\n// Template\n

{{ fullName }}

\n

{{ fullName }}

\n

{{ getFullName() }}

\n

{{ getFullName() }}

\n```\n\nВывод: используйте **computed для данных**, **methods для действий**.\n\n### Writable Computed (с setter)\n\n```javascript\nconst firstName = ref('Иван');\nconst lastName = ref('Петров');\n\nconst fullName = computed({\n // Getter\n get() {\n return firstName.value + ' ' + lastName.value;\n },\n // Setter - вызывается когда меняете computed свойство\n set(newValue) {\n [firstName.value, lastName.value] = newValue.split(' ');\n }\n});\n\n// Использование\nconsole.log(fullName.value); // \"Иван Петров\"\nfullName.value = 'Петр Сидоров'; // Вызывает setter\nconsole.log(firstName.value); // \"Петр\"\nconsole.log(lastName.value); // \"Сидоров\"\n```\n\n### Практический пример: Todo фильтр\n\n```javascript\n\n\n\n\n\n```\n\n### Computed vs Watch\n\n```javascript\nconst firstName = ref('Иван');\nconst lastName = ref('Петров');\nconst fullName = ref('');\n\n// COMPUTED - использует для трансформаций данных\nconst computedFullName = computed(() => {\n return firstName.value + ' ' + lastName.value;\n});\n\n// WATCH - использует для side effects (API запросы, логирование)\nwatch([firstName, lastName], ([first, last]) => {\n console.log(`Пользователь изменил имя на ${first} ${last}`);\n // Отправляем на сервер\n updateUserProfile(first, last);\n});\n```\n\n### Важные правила\n\n1. **Не изменяйте состояние в computed!**\n```javascript\n// ПЛОХО\nconst badComputed = computed(() => {\n count.value++; // Побочный эффект!\n return count.value;\n});\n```\n\n2. **Не делайте async операции в computed!**\n```javascript\n// ПЛОХО\nconst badComputed = computed(async () => {\n const data = await fetch('/api/data');\n return data;\n});\n\n// ПРАВИЛЬНО - используйте watch\nconst data = ref(null);\nwatch(searchTerm, async (newSearch) => {\n data.value = await fetch(`/api/search?q=${newSearch}`);\n});\n```\n\n3. **Зависимости должны быть явными**\n```javascript\n// Vue автоматически отслеживает зависимости\nconst fullName = computed(() => {\n // Vue видит что используются firstName и lastName\n return firstName.value + ' ' + lastName.value;\n}); // Пересчитается при изменении любого из них\n```\n\n### Заключение\n\n**Computed** в Vue - это:\n- Кешированные вычисляемые свойства\n- Автоматически пересчитываются при изменении зависимостей\n- Идеальны для трансформаций и фильтрации данных\n- Улучшают производительность (за счет кеша)\n- Делают код чище и понятнее\n- Альтернатива методам для данных (не для действий)\n\nИспользуйте computed для всех вычислений данных - это best practice во Vue!","dateCreated":"2026-04-02T22:13:31.533962","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Зачем нужен Computed во Vue?

2.3 Middle🔥 191 комментариев
#Vue.js

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Computed в Vue

Основное назначение

Computed (вычисляемые свойства) - это функции в Vue, которые автоматически пересчитываются когда меняются их зависимости. Главный плюс - они кешируют результат и не пересчитываются, если зависимости не изменились. Это мощный инструмент для производительности и чистого кода.

Проблема без Computed

// ПЛОХО - пересчитывается при КАЖДОМ render-е
<template>
  <div>
    <input v-model="firstName">
    <input v-model="lastName">
    <!-- Вызывается функция при каждом render-е! -->
    <p>{{ firstName + ' ' + lastName }}</p>
    <p>{{ (firstName + ' ' + lastName).toUpperCase() }}</p>
    <p>{{ (firstName + ' ' + lastName).length }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
const firstName = ref('Иван');
const lastName = ref('Петров');
// Логика повторяется 3 раза!
// Не очень читаемо
// Пересчитывается при КАЖДОМ render-е
</script>

Решение с Computed

Vue 3 (Composition API)

<template>
  <div>
    <input v-model="firstName">
    <input v-model="lastName">
    <!-- Используем computed, пересчитывается только если deps изменились -->
    <p>{{ fullName }}</p>
    <p>{{ fullNameUpper }}</p>
    <p>{{ fullNameLength }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

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

// Только читаемое свойство
const fullName = computed(() => {
  console.log('fullName пересчитана'); // Выполнится только при изменении
  return firstName.value + ' ' + lastName.value;
});

const fullNameUpper = computed(() => fullName.value.toUpperCase());
const fullNameLength = computed(() => fullName.value.length);
</script>

Vue 2 (Options API)

<template>
  <div>
    <input v-model="firstName">
    <input v-model="lastName">
    <p>{{ fullName }}</p>
    <p>{{ fullNameUpper }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      firstName: 'Иван',
      lastName: 'Петров'
    };
  },
  computed: {
    fullName() {
      console.log('fullName пересчитана');
      return this.firstName + ' ' + this.lastName;
    },
    fullNameUpper() {
      return this.fullName.toUpperCase();
    }
  }
};
</script>

Ключевые преимущества

1. Кеширование (Memoization)

const expensiveComputation = computed(() => {
  // Эта функция вызывается только если dependencies изменились!
  console.log('Дорогостоящий расчет...');
  
  let sum = 0;
  for (let i = 0; i < 1000000; i++) {
    sum += i; // Тяжелый расчет
  }
  return sum;
});

// Выполнение:
// 1. expensiveComputation.value → логирует, вычисляет
// 2. expensiveComputation.value → логирует НЕ вычисляет, возвращает кеш
// 3. expensiveComputation.value → логирует НЕ вычисляет, возвращает кеш
// Логируется только один раз!

2. Чистота кода

// ПЛОХО - inline логика в template
<div v-if="user && user.profile && user.profile.verified">Verified</div>
<span>{{ user && user.profile && user.profile.name }}</span>

// ХОРОШО - используем computed
const isVerified = computed(() => user.value?.profile?.verified ?? false);
const userName = computed(() => user.value?.profile?.name ?? 'Unknown');

<div v-if="isVerified">Verified</div>
<span>{{ userName }}</span>

3. Реактивность

const price = ref(100);
const quantity = ref(5);
const taxRate = ref(0.1);

const total = computed(() => {
  // Автоматически пересчитывается при изменении price, quantity или taxRate
  return price.value * quantity.value;
});

const totalWithTax = computed(() => {
  // Зависит от total, которая зависит от других переменных
  return total.value * (1 + taxRate.value);
});

// При изменении price:
price.value = 200; // total автоматически пересчитается
                   // totalWithTax автоматически пересчитается

4. Фильтрация и сортировка списков

const items = ref([  { name: 'Apple', price: 100 },
  { name: 'Banana', price: 50 },
  { name: 'Cherry', price: 80 }
]);

const searchQuery = ref('');
const sortBy = ref('price'); // 'name' или 'price'

// Фильтруем и сортируем
const filteredItems = computed(() => {
  return items.value
    .filter(item => item.name.includes(searchQuery.value))
    .sort((a, b) => {
      if (sortBy.value === 'name') return a.name.localeCompare(b.name);
      return a.price - b.price;
    });
});

// Template
<div>
  <input v-model="searchQuery" placeholder="Search...">
  <select v-model="sortBy"><option>name</option><option>price</option></select>
  <ul>
    <li v-for="item in filteredItems" :key="item.name">
      {{ item.name }} - {{ item.price }}
    </li>
  </ul>
</div>

Computed vs Methods

// COMPUTED - кешируется
const fullName = computed(() => {
  console.log('computed triggered');
  return firstName.value + ' ' + lastName.value;
});

// METHOD - вызывается каждый раз
const getFullName = () => {
  console.log('method triggered');
  return firstName.value + ' ' + lastName.value;
};

// Template
<p>{{ fullName }}</p>      <!-- computed: логирует 1 раз -->
<p>{{ fullName }}</p>      <!-- computed: логирует НЕ выполняется -->
<p>{{ getFullName() }}</p> <!-- method: логирует каждый раз -->
<p>{{ getFullName() }}</p> <!-- method: логирует каждый раз -->

Вывод: используйте computed для данных, methods для действий.

Writable Computed (с setter)

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

const fullName = computed({
  // Getter
  get() {
    return firstName.value + ' ' + lastName.value;
  },
  // Setter - вызывается когда меняете computed свойство
  set(newValue) {
    [firstName.value, lastName.value] = newValue.split(' ');
  }
});

// Использование
console.log(fullName.value); // "Иван Петров"
fullName.value = 'Петр Сидоров'; // Вызывает setter
console.log(firstName.value); // "Петр"
console.log(lastName.value); // "Сидоров"

Практический пример: Todo фильтр

<template>
  <div>
    <input v-model="newTodo" @keyup.enter="addTodo">
    <button @click="addTodo">Add</button>
    
    <div>
      <button
        @click="filter = 'all'"
        :class="{ active: filter === 'all' }"
      >
        All ({{ allTodos.length }})
      </button>
      <button
        @click="filter = 'active'"
        :class="{ active: filter === 'active' }"
      >
        Active ({{ activeTodos.length }})
      </button>
      <button
        @click="filter = 'completed'"
        :class="{ active: filter === 'completed' }"
      >
        Completed ({{ completedTodos.length }})
      </button>
    </div>
    
    <ul>
      <li v-for="todo in filteredTodos" :key="todo.id">
        <input
          type="checkbox"
          v-model="todo.completed"
        >
        <span :class="{ completed: todo.completed }">{{ todo.text }}</span>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

const todos = ref([
  { id: 1, text: 'Learn Vue', completed: true },
  { id: 2, text: 'Build app', completed: false }
]);

const newTodo = ref('');
const filter = ref('all');

const allTodos = computed(() => todos.value);

const activeTodos = computed(() => {
  return todos.value.filter(t => !t.completed);
});

const completedTodos = computed(() => {
  return todos.value.filter(t => t.completed);
});

const filteredTodos = computed(() => {
  switch (filter.value) {
    case 'active': return activeTodos.value;
    case 'completed': return completedTodos.value;
    default: return allTodos.value;
  }
});

const addTodo = () => {
  if (!newTodo.value) return;
  todos.value.push({
    id: Math.max(...todos.value.map(t => t.id), 0) + 1,
    text: newTodo.value,
    completed: false
  });
  newTodo.value = '';
};
</script>

<style scoped>
.active {
  font-weight: bold;
  color: blue;
}
.completed {
  text-decoration: line-through;
  color: gray;
}
</style>

Computed vs Watch

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

// COMPUTED - использует для трансформаций данных
const computedFullName = computed(() => {
  return firstName.value + ' ' + lastName.value;
});

// WATCH - использует для side effects (API запросы, логирование)
watch([firstName, lastName], ([first, last]) => {
  console.log(`Пользователь изменил имя на ${first} ${last}`);
  // Отправляем на сервер
  updateUserProfile(first, last);
});

Важные правила

  1. Не изменяйте состояние в computed!
// ПЛОХО
const badComputed = computed(() => {
  count.value++; // Побочный эффект!
  return count.value;
});
  1. Не делайте async операции в computed!
// ПЛОХО
const badComputed = computed(async () => {
  const data = await fetch('/api/data');
  return data;
});

// ПРАВИЛЬНО - используйте watch
const data = ref(null);
watch(searchTerm, async (newSearch) => {
  data.value = await fetch(`/api/search?q=${newSearch}`);
});
  1. Зависимости должны быть явными
// Vue автоматически отслеживает зависимости
const fullName = computed(() => {
  // Vue видит что используются firstName и lastName
  return firstName.value + ' ' + lastName.value;
}); // Пересчитается при изменении любого из них

Заключение

Computed в Vue - это:

  • Кешированные вычисляемые свойства
  • Автоматически пересчитываются при изменении зависимостей
  • Идеальны для трансформаций и фильтрации данных
  • Улучшают производительность (за счет кеша)
  • Делают код чище и понятнее
  • Альтернатива методам для данных (не для действий)

Используйте computed для всех вычислений данных - это best practice во Vue!