Skip to content

Сторы

Стор хранит значение модели. Если приложению нужно что-то помнить между событиями, это почти всегда стор: текст поля, выбранный id, список сообщений, статус формы, кешированные данные.

ts
const query = store("");
const profile = store({ name: "Ada", age: 36 });

Стор не является глобальной переменной. Он описывает, какое значение существует в модели, а конкретное значение лежит в scope. Поэтому один и тот же стор может иметь разные значения в разных scopes.

ts
const first = scope();
const second = scope();

scoped(first, () => {
  query.value = "docs";
});

scoped(second, () => {
  query.value = "api";
});

В первом scope у query будет "docs", во втором — "api". Код модели при этом один и тот же.

Чтение и запись

Сторы с примитивными значениями читаются через .value.

ts
count.value += 1;

Сторы с объектами раскрывают поля напрямую.

ts
profile.age += 1;

Прямое чтение или запись требуют scope в текущем контексте выполнения. Если код не находится внутри реакции, effect handler или другой ветки, где scope уже известен, откройте его через scoped(scope, fn).

Derived-сторы

Derived-стор нужен, когда значение полностью следует из другого значения. Например, label поиска можно вычислить из query, а не обновлять вручную в каждой реакции.

ts
const queryLabel = query.map((text) => (text ? `Searching: ${text}` : "Search"));

Derived-сторы ленивые. Если на такой стор не подписана реакция или UI, изменение source-стора только помечает его кеш грязным. Пересчет произойдет позже, когда значение явно прочитают. Если derived-стор активен, например на него подписана реакция, изменение зависимостей сразу пересчитает значение и запустит подписчиков только при реальном изменении результата.

Если значение зависит от события во времени, это уже не derived-стор. Тогда лучше хранить обычный стор и менять его через реакцию.

Ленивые вычисления

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

ts
const query = store("");
const users = store({ items: [] as User[] });

const visibleUsers = computed(() => {
  const text = query.value.toLowerCase();

  return users.items.filter((user) => user.name.toLowerCase().includes(text));
});

visibleUsers ведет себя как read-only стор. Первый read в scope выполнит функцию и запомнит результат. Следующие чтения вернут кеш. Когда query или users изменятся в этом же scope, кеш станет грязным, но значение не пересчитается, пока его снова не прочитают или пока его не наблюдает реакция, подписка или UI.

Обычный store() считается активным всегда: запись должна сохранить новое значение. Derived-сторы активируются только наблюдением. Используйте map, когда нужен простой derived-стор от одного источника. Используйте computed, когда вычисление дорогое, зависит от нескольких сторов или зависит от веток внутри самой функции.