Computed
Computed автоматически вычисляется из observables и кешируется до изменения зависимостей.
Ключевые особенности
- ✅ Кеширование - вычисляется только при изменении зависимостей
- ✅ Автоматическое обновление - пересчитывается когда observable меняется
- ✅ Ленивое вычисление - не вычисляется пока не запросят
- ✅ Оптимизация - кеш между обращениями
Базовый пример
import { makeAutoObservable } from 'mobx';
class Store {
items = [1, 2, 3, 4, 5];
constructor() {
makeAutoObservable(this);
}
get sum() {
console.log('Вычисляем...');
return this.items.reduce((a, b) => a + b, 0);
}
}
const store = new Store();
console.log(store.sum);
console.log(store.sum);
console.log(store.sum);
Результат: "Вычисляем..." выведется только 1 раз!
Computed vs обычный getter
Без computed:
class Store {
items = [1, 2, 3];
get sum() {
return this.items.reduce((a, b) => a + b, 0);
}
}
Вычисляется каждый раз при обращении ❌
С computed:
class Store {
items = [1, 2, 3];
constructor() {
makeAutoObservable(this);
}
get sum() {
return this.items.reduce((a, b) => a + b, 0);
}
}
Вычисляется один раз и кешируется ✅
Цепочки computed
Computed может зависеть от других computed:
class Store {
products = [];
vatRate = 0.2;
constructor() {
makeAutoObservable(this);
}
get subtotal() {
return this.products.reduce((sum, p) => sum + p.price, 0);
}
get vat() {
return this.subtotal * this.vatRate;
}
get total() {
return this.subtotal + this.vat;
}
}
Каждый computed кешируется отдельно!
Отслеживание зависимостей
Computed отслеживает только используемые observables:
class Store {
user = {
name: "Ivan",
surname: "Petrov",
age: 25
};
constructor() {
makeAutoObservable(this);
}
get fullName() {
return `${this.user.name} ${this.user.surname}`;
}
}
const store = new Store();
autorun(() => {
console.log(store.fullName);
});
store.user.age = 30;
fullName не пересчитается при изменении age, потому что не использует это поле!
Best Practices
✅ Хорошо:
get totalPrice() {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
❌ Плохо - side-эффекты:
get totalPrice() {
console.log('Считаем...');
analytics.track('calculation');
return this.items.reduce((sum, item) => sum + item.price, 0);
}
Computed должен быть чистой функцией без side-эффектов!
🎮 Интерактивный пример
Ваш пример из практики - computed отслеживает только используемые поля:
Computed - отслеживание зависимостей
class Store {
user = {
surname: "",
name: "",
age: 0,
};
constructor() {
makeAutoObservable(this);
}
get fullName() {
console.log('🔄 Вычисляем fullName...');
return `${this.user.surname} ${this.user.name}`;
}
}
const store = new Store();
reaction(
() => store.fullName,
(fullName) => {
console.log('✅ fullName изменился:', fullName);
}
);
console.log('--- Изменяем AGE (не влияет на fullName) ---');
runInAction(() => {
store.user.age = 15;
});
console.log('\n--- Изменяем NAME (влияет на fullName) ---');
runInAction(() => {
store.user.name = "Dmitriy";
});
console.log('\n--- Изменяем NAME снова ---');
runInAction(() => {
store.user.name = "Shirmanov";
});Что демонстрирует: изменение age НЕ запускает пересчет fullName, потому что computed отслеживает только используемые зависимости!
🎯 3. Проверьте себя
Тест: Computed
1 / 5🎴 4. Anki карточки
Карточки для Anki
8 карточек- Нажмите "Скачать для Anki"
- В Anki: Файл → Импортировать
- Выберите скачанный .csv файл
- Тип: "Базовый (с обратной карточкой)"
- Разделитель полей: Запятая
- Импортировать!
📊 Результат обучения
После изучения этой темы вы:
- ✅ Понимаете как работает computed и кеширование
- ✅ Знаете про отслеживание зависимостей
- ✅ Умеете оптимизировать вычисления
- ✅ Прошли тест на понимание
- ✅ Получили карточки для Anki
Следующий шаг: изучите Reactions - реакции на изменения! 🚀