Store API

import { type Store, type StoreWritable, createStore } from "effector";

const $store = createStore();

Store — это объект, который хранит значение состояния. Обновление стора происходит когда новое значение не равно (!==) текущему, а также когда не равно undefined (если в конфигурации стора не указан skipVoid:false). Стор является Unit. Некоторые сторы могут быть производными.

Кто такой этот ваш стор?

Если вы еще не знакомы как работать со стором, то добро пожаловать сюда.

Интерфейс стора

Доступные методы и свойства стора:

Метод/СвойствоОписание
map(fn)Создает новый производный стор
on(trigger, reducer) Обновление стейта c помощью reducer, когда вызван trigger
watch(watcher)Вызывает функцию watcher каждый раз, когда стор обновляется
reset(...triggers)Метод для сброса к начальному состоянию
off(trigger)Удаляет подписку на указанный триггер
updates()Событие срабатывающие при обновление стора
reinit()Событие для реинициализации стора
shortNameID или короткое имя store
defaultStateНачальное состояние стора
getState()Возвращает текущий стейт

Иммутабельность

Store в effector иммутабелен. Это значит, что обновления в нём будут происходить только если в функции-обработчике (например combine, sample или on) вернуть новый объект

Например, прежде чем использовать методы массива, нужно создать новую ссылку на него. Как правильно:

$items.on(addItem, (items, newItem) => {
  const updatedItems = [...items];
  // ✅ метод .push вызывается на новом массиве
  updatedItems.push(newItem);
  return updatedItems;
});

Так делать нельзя, обновления стора не произойдёт

$items.on(addItem, (items, newItem) => {
  // ❌ ошибка! Ссылка на массив осталась та же, обновления стора не произойдёт
  items.push(newItem);
  return items;
});

Обновление объектов происходит аналогичным образом

Сторы в effector должен быть размером как можно меньше, чтобы отвечать за конкретную часть в бизнес логике, в отличии от например redux стора, который имеет тенденцию к тому чтобы держать рядом всё и сразу. Когда состояние атомарное, то необходимости в спредах объектов становится меньше. Однако, если возникает потребность часто обновлять сильно вложенные данные, для обновления состояния допустимо применять immer чтобы упростить повторяющийся код

Методы стора

.map(fn)

Принимает функцию fn и возвращает производный стор, который автоматически обновляется, когда исходный стор изменяется.

  • Формула
$source.map(fn, config?);
  • Тип
const $derived = $source.map<T>(
  fn: (value: SourceValue) => T,
  config?: {
    skipVoid?: boolean
  }
): Store<T>
  • Примеры

Базовое использование:

import { createEvent, createStore } from "effector";

const changed = createEvent<string>();

const $title = createStore("");
const $titleLength = $title.map((title) => title.length);

$title.on(changed, (_, newTitle) => newTitle);

$titleLength.watch((length) => {
  console.log("new length", length);
});

changed("hello");
changed("world");
changed("hello world");

Попробовать

Вторым аргументом можно передать объект конфига со значением skipVoid:false, тогда стор сможет принимать undefined значения:

const $titleLength = $title.map((title) => title.length, { skipVoid: false });
  • Детальное описание

Метод map вызывает переданную функцию fn с состоянием исходного стора в аргументе, каждый раз когда оригинальный стор обновляется.
Результат выполнения функции используется как значение стора.

  • Возвращаемое значение

Возвращает новый производный стор.

.on(trigger, reducer)

Обновляет состояние используя reducer, при срабатывании trigger.

  • Формула
$store.on(trigger, reducer);
  • Тип
$store.on<T>(
  trigger: Unit<T> | Unit<T>[]
  reducer: (state: State, payload: T) => State | void
): this
  • Примеры
import { createEvent, createStore } from "effector";

const $counter = createStore(0);
const incrementedBy = createEvent<number>();

$counter.on(incrementedBy, (value, incrementor) => value + incrementor);

$counter.watch((value) => {
  console.log("updated", value);
});

incrementedBy(2);
incrementedBy(2);

Попробовать

  • Возвращаемое значение

Возвращает текущий стор.

.watch(watcher)

Вызывает функцию watcher каждый раз, когда стор обновляется.

  • Формула
const unwatch = $store.watch(watcher);
  • Тип
$store.watch(watcher: (state: State) => any): Subscription
  • Примеры
import { createEvent, createStore } from "effector";

const add = createEvent<number>();
const $store = createStore(0);

$store.on(add, (state, payload) => state + payload);

$store.watch((value) => console.log(`current value: ${value}`));

add(4);
add(3);

Попробовать

  • Возвращаемое значение

Возвращает функцию для отмены подписки.

.reset(...triggers)

Сбрасывает состояние стора до значения по умолчанию при срабатывании любого trigger.

  • Формула
$store.reset(...triggers);
  • Тип
$store.reset(...triggers: Array<Unit<any>>): this
  • Примеры
import { createEvent, createStore } from "effector";

const increment = createEvent();
const reset = createEvent();

const $store = createStore(0)
  .on(increment, (state) => state + 1)
  .reset(reset);

$store.watch((state) => console.log("changed", state));

increment();
increment();
reset();

Попробовать

  • Возвращаемое значение

Возвращает текущий стор.

.off(trigger)

Удаляет reducer для указанного trigger.

  • Формула
$store.off(trigger);
  • Тип
$store.off(trigger: Unit<any>): this
  • Примеры
import { createEvent, createStore, merge } from "effector";

const changedA = createEvent();
const changedB = createEvent();

const $store = createStore(0);
const changed = merge([changedA, changedB]);

$store.on(changed, (state, params) => state + params);
$store.off(changed);

Попробовать

  • Возвращаемое значение

Возвращает текущий стор.

Свойства стора

.updates

Событие срабатывающие при обновление стора.

  • Примеры
import { createStore, is } from "effector";

const $clicksAmount = createStore(0);
is.event($clicksAmount.updates); // true

$clicksAmount.updates.watch((amount) => {
  console.log(amount);
});

Попробовать

  • Возвращаемое значение

Производное событие, представляющее обновления данного стора.

.reinit

Событие для реинициализации стора.

  • Примеры
import { createStore, createEvent, sample, is } from "effector";

const $counter = createStore(0);
is.event($counter.reinit);

const increment = createEvent();

$counter.reinit();
console.log($counter.getState());

Попробовать

  • Возвращаемое значение

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

.shortName

Cтроковое свойство, которое содержит ID или короткое имя стора.

  • Примеры
const $store = createStore(0, {
  name: "someName",
});

console.log($store.shortName); // someName

Попробовать

  • Возвращаемое значение

ID или короткое имя store.

.defaultState

Свойство, которое содержит значение состояния по умолчанию стора.

  • Пример
const $store = createStore("DEFAULT");

console.log($store.defaultState === "DEFAULT"); // true
  • Возвращаемое значение

Значение состояния по умолчанию.

Вспомогательные методы

.getState()

Метод, который возвращает текущее состояние стора.

Осторожно!

getState() не рекомендуется использовать в бизнес-логике - лучше передавать данные через sample.

  • Примеры
import { createEvent, createStore } from "effector";

const add = createEvent<number>();

const $number = createStore(0).on(add, (state, data) => state + data);

add(2);
add(3);

console.log($number.getState());

Попробовать

  • Возвращаемое значение

Текущее состояние стора.

  • createStore - Создает новый стор
  • combine - Комбинирует несколько сторов и возращает новый производный стор
  • sample - Ключевой оператор для построения связей между юнитами
  • createEvent - Создает события
  • createEffect - Создает эффекты
Перевод поддерживается сообществом

Документация на английском языке - самая актуальная, поскольку её пишет и обновляет команда effector. Перевод документации на другие языки осуществляется сообществом по мере наличия сил и желания.

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

Соавторы