Перейти к основному содержимому

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
Когда пересчитывается computed value?
A.При каждом обращении к нему
B.Только когда изменяются его зависимости
C.Раз в секунду
D.Никогда, кешируется навсегда
📊 Прогресс: 0 / 5 вопросов

🎴 4. Anki карточки

Карточки для Anki

8 карточек
📝 Что такое Computed в MobX?
📝 Когда пересчитывается computed?
📝 Computed отслеживает все observable в объекте?
📝 Разница между computed и обычным getter?
📝 Можно ли в computed делать console.log или API запросы?
📝 Как создать computed в классе?
📝 Что такое ленивое вычисление (lazy evaluation) в computed?
📝 Могут ли computed зависеть от других computed?
💡 Как импортировать в Anki:
  1. Нажмите "Скачать для Anki"
  2. В Anki: Файл → Импортировать
  3. Выберите скачанный .csv файл
  4. Тип: "Базовый (с обратной карточкой)"
  5. Разделитель полей: Запятая
  6. Импортировать!

📊 Результат обучения

После изучения этой темы вы:

  • ✅ Понимаете как работает computed и кеширование
  • ✅ Знаете про отслеживание зависимостей
  • ✅ Умеете оптимизировать вычисления
  • ✅ Прошли тест на понимание
  • ✅ Получили карточки для Anki

Следующий шаг: изучите Reactions - реакции на изменения! 🚀