Store (стор) – это объект, который хранит значение состояния, то есть какие-либо данные. Стор обновляется при получении значения, которое не равно (!==
) текущему и undefined
. Является юнитом
Методы
map(fn)
Создает производный стор на основе данных из исходного
Формула
declare const $first: Store<T>; // исходный стор
let $second: Store<S>; // производный стор
$second = $first.map(/*fn*/ (state: T) => S);
При обновлении исходного стора $first
, функция-обработчик fn
будет вызвана с новым состоянием $first
и последним состоянием $second
, результат вычислений будет сохранён в производном сторе $second
, то есть реактивно обновит его значение
С версии effector 21.8.0 второй аргумент функции fn
и firstState
были депрекейтнуты, вместо этого используйте updateFilter или создание нового стора с помощью createStore
.
Аргументы
fn
:(state: T) => S
Функция-обработчик, которая будет вычислять новое состояние производного стора
$second
на основе значения исходного стора$first
. Функция также генерирует и исходное состояние стора, поэтому в первый раз запускается в момент вызова.map
, то есть ещё до создания производного стора. Должна быть чистойАргументы
state
: Текущее состояние исходного стора$first
на момент начала работыfn
Возвращает
Новое значение для хранения в производном сторе
$second
. Если функция возвращает undefined или текущее состояние производного стора, то обновления не будет
Возвращает
Новый, производный стор
Пример
import { createEvent, createStore } from "effector";
const changed = createEvent();
const title = createStore("").on(changed, (_, newTitle) => newTitle);
const length = title.map((title) => title.length);
length.watch((length) => {
console.log("длина строки", length);
});
// => длина строки 0
changed("hello");
// => длина строки 5
changed("world");
// ничего не произошло
changed("hello world");
// => длина строки 11
on(trigger, reducer)
Обновляет состояние стора с помощью функции-обработчика при срабатывании триггера
Формула
declare const $store: Store<T>; // обновляемый стор
declare const event: Event<S>; // триггер обновления
declare const fx: Effect<S, any>; // триггер обновления
declare const $storeB: Store<S>; // триггер обновления
$store.on(/*clock*/ event, /*fn*/ (state: T, data: S) => T);
$store.on(/*clock*/ fx, /*fn*/ (state: T, data: S) => T);
$store.on(/*clock*/ $storeB, /*fn*/ (state: T, data: S) => T);
$store.on(/*clock*/ [event, fx, $storeB], /*fn*/ (state: T, data: S) => T);
Аргументы
trigger
: Юнит или массив юнитовТриггер начала вычисления или несколько триггеров. Для каждого триггера последний установленный обработчик будет заменять предыдущие обработчики (полезно для динамического поведения)
Разновидности:
- событие или эффект: срабатывание этого события/эффекта будет запускать обновление
$store
- стор: обновление этого стора будет запускать обновление
$store
- массив юнитов: срабатывание любого из юнитов будет запускать обновление
$store
- событие или эффект: срабатывание этого события/эффекта будет запускать обновление
reducer
:(state: T, data: S) => T
Функция-обработчик, которая будет вычислять новое состояние
$store
на основе его предыдущего состояния и данных изtrigger
, должна быть чистойАргументы
state
: Текущее состояние стора на момент начала работыfn
data
: Данные, принятые от сработавшегоtrigger
Разновидности, в зависимости от типа сработавшего
trigger
:- событие: значение, с которым было вызвано событие
- эффект: значение, с которым был вызван эффект
- стор: новое значение стора
Возвращает
Новое значение для хранения в
$store
. Если функция возвращает undefined или текущее состояние стора, то обновления не будет
Возвращает
Текущий стор
Поддержка массивов в trigger
добавлена в effector 20.15.0
Пример
import { createEvent, createStore } from "effector";
const store = createStore(0);
const trigger = createEvent();
store.on(trigger, (state, data) => state + data);
store.watch((value) => {
console.log(value);
});
// => 0
trigger(2);
// => 2
trigger(2);
// => 4
Использование массива юнитов в trigger
import { createEvent, createStore } from "effector";
const store = createStore(0);
const triggerA = createEvent();
const triggerB = createEvent();
store.on([triggerA, triggerB], (state, data) => state + data);
store.watch((value) => {
console.log(value);
});
// => 0
triggerA(2);
// => 2
triggerB(2);
// => 4
watch(watcher)
Вызывает функцию с сайд-эффектами при каждом обновлении стора. В первый раз вызывается сразу же при создании, с текущим значением стора
Формула
declare const $store: Store<T>
$store.watch(/*watcher*/ (state: T) => any)
-> Subscription
Аргументы
watcher
:(state: T) => any
Функция с сайд-эффектами, получает текущее состояние стора в качестве первого аргумента. Возвращаемое значение не используется
Возвращает
Subscription: Функция отмены подписки, после её вызова watcher
перестаёт получать обновления и удаляется из памяти. Повторные вызовы функции отмены подписки не делают ничего
Пример
const add = createEvent();
const store = createStore(0).on(add, (state, payload) => state + payload);
store.watch((value) => {
console.log(`текущее значение: ${value}`);
});
// => текущее значение: 0
add(4);
// => текущее значение: 4
add(3);
// => текущее значение: 7
reset(...triggers)
Сбрасывает состояние стора к исходному значению при срабатывании триггера
Формула
declare const $store: Store<T>; // обновляемый стор
declare const event: Event<any>; // триггер обновления
declare const fx: Effect<any, any>; // триггер обновления
declare const $storeB: Store<any>; // триггер обновления
$store.reset(/*clock*/ event);
$store.reset(/*clock*/ fx);
$store.reset(/*clock*/ $storeB);
$store.reset(/*clock*/ [event, fx, $storeB]);
$store.reset(/*clock*/ ...[event, fx, $storeB]);
Аргументы
trigger
: Юнит или массив юнитовТриггер запуска обновления стора или несколько триггеров. Если на момент срабатывания стор уже находится в исходном состоянии, то обновления не будет
Разновидности:
- событие или эффект: срабатывание этого события/эффекта будет запускать обновление
$store
- стор: обновление этого стора будет запускать обновление
$store
- массив юнитов: срабатывание любого из юнитов будет запускать обновление
$store
- событие или эффект: срабатывание этого события/эффекта будет запускать обновление
Возвращает
Текущий стор
Поддержка массивов в trigger
добавлена в effector 20.15.0
Пример
import { createEvent, createStore } from "effector";
const store = createStore(0);
const increment = createEvent();
const resetTrigger = createEvent();
store.on(increment, (state) => state + 1);
store.reset(resetTrigger);
store.watch((state) => {
console.log(state);
});
// => 0
increment();
// => 1
increment();
// => 2
resetTrigger();
// => 0
resetTrigger();
// ничего не произошло (стор уже находится в исходном состоянии)
Использование массива юнитов в trigger
import { createEvent, createStore } from "effector";
const store = createStore(0);
const increment = createEvent();
const triggerA = createEvent();
const triggerB = createEvent();
store.on(increment, (state) => state + 1);
store.reset([triggerA, triggerB]);
store.watch((state) => {
console.log(state);
});
// => 0
increment();
// => 1
increment();
// => 2
triggerA();
// => 0
triggerB();
// ничего не произошло (стор уже находится в исходном состоянии)
off(trigger)
Удаляет обработчик для данного триггера, который был установлен через .on или .reset. Если для данного триггера не было обработчика, этот метод ничего не делает
declare const $store: Store<any>; // обновляемый стор
declare const event: Event<any>; // триггер обновления
declare const fx: Effect<any, any>; // триггер обновления
declare const $storeB: Store<any>; // триггер обновления
$store.off(/*clock*/ event);
$store.off(/*clock*/ fx);
$store.off(/*clock*/ $storeB);
Аргументы
trigger
: Юнит-триггер
Возвращает
Текущий стор
Пример
import { createEvent, createStore } from "effector";
const click = createEvent();
const $clicks = createStore(0);
$clicks.on(click, (n) => n + 1);
$clicks.watch((n) => {
console.log(n);
});
// => 0
click();
// => 1
$clicks.off(click);
click();
// ничего не произошло
thru(fn)
Вызывает функцию с заданным стором и возвращает результат как есть. Используется для последовательных трансформаций заранее описанными функциями пока в javascript не добавлен pipeline proposal
Формула
declare const $store: Store<T>;
const result: S = $store.thru(/*fn*/ (store: Store<T>) => S);
Аргументы
fn
:(store: Store<T>) => S
Функция, которая получает сам стор в аргументы и возвращает некоторое значение, должна быть чистой
Возвращает
Любое значение, которое вернёт fn
Пример
import { createStore, createEvent } from "effector";
const enhance = (fn) => (store) => store.map(fn);
const inc = createEvent();
const $num = createStore(1);
$num.on(inc, (n) => n + 1);
//prettier-ignore
const $result = $num
.thru(enhance(x => x + 1))
.thru(enhance(x => x * 10))
$num.watch((n) => {
console.log("num", n);
});
// => num 1
$result.watch((n) => {
console.log("result", n);
});
// => result 20
inc();
// => num 2
// => result 30
Свойства
updates
Дочернее событие стора, будет вызвано при каждом обновлении стора. Используется только для определения сайд-эффектов через store.updates.watch, где будут срабатывать начиная с первого обновления, в отличие от store.watch, обработчики в котором запускаются при создании немедленно
Это свойство управляется самим стором.
По мере усложнения логики проекта оптимальнее заменить на комбинацию эффекта и sample
Формула
declare const $store: Store<T>
$store.updates
-> Event<T>
Пример
Вызов сайд-эффектов начиная с первого обновления
import { createStore, createEvent } from "effector";
const click = createEvent();
const clicksAmount = createStore(0);
clicksAmount.on(click, (n) => n + 1);
clicksAmount.watch((amount) => {
console.log("вызов с текущим состоянием, включая исходное", amount);
});
// => вызов с текущим состоянием, включая исходное 0
clicksAmount.updates.watch((amount) => {
console.log("вызов с текущим состоянием, начиная с первого обновления", amount);
});
// ничего не произошло
click();
// => вызов с текущим состоянием, включая исходное 1
// => вызов с текущим состоянием, начиная с первого обновления 1
shortName
Имя стора. Задаётся либо явно, через поле name
в createStore, либо автоматически через Babel plugin. Используется для обработки сущностей программно, например при использовании хуков домена
Формула
declare const $store: Store<any>
$store.shortName
-> string
Пример
import { createDomain, createEvent } from "effector";
const increment = createEvent();
const storesDomain = createDomain();
storesDomain.onCreateStore((store) => {
console.log(`создан стор '${store.shortName}'`);
store.watch((value) => {
console.log(`значение стора '${store.shortName}':`, value);
});
});
const $foo = storesDomain.createStore(0, { name: "foo" });
// => создан стор 'foo'
// => значение стора 'foo': 0
const $bar = storesDomain.createStore(0, { name: "bar" });
// => создан стор 'bar'
// => значение стора 'bar': 0
$foo.on(increment, (n) => n + 1);
increment();
// => значение стора 'foo': 1
defaultState
Начальное состояние стора, то, с которым он создавался. К этому состоянию будет возвращать метод reset
Формула
declare const $store: Store<T>
$store.defaultState
-> T
Пример
const $store = createStore("DEFAULT");
console.log($store.defaultState === "DEFAULT");
// => true
sid
Стабильный идентификатор стора. Задаётся автоматически через Babel plugin
Формула
declare const $store: Store<any>
$store.sid
-> string | null
Дополнительные методы
getState()
Возвращает текущее значение стора
Формула
declare const $store: Store<T>;
const currentValue: T = $store.getState();
Пример
import { createEvent, createStore } from "effector";
const add = createEvent();
const $number = createStore(0);
$number.on(add, (state, data) => state + data);
$number.watch((n) => {
console.log(n);
});
// => 0
add(2);
// => 2
add(3);
// => 5
watch(trigger, watcher)
Сокращённая запись для описания сайд-эффекта, который необходимо запускать только при срабатывании определённого триггера и в котором необходимо как состояние стора так и данные из триггера
По мере усложнения логики проекта оптимальнее заменить на attach
Формула
declare const $store: Store<T>
declare const trigger: Event<S>
$store.watch(
/*clock*/ trigger,
/*fn*/ (state: T, data: S) => any,
)
-> Subscription
Аргументы
trigger
: Юнит-триггерfn
:(state: T, data: S) => any
Функция с сайд-эффектами. Возвращаемое значение не используется
Аргументы
state
: Текущее состояние стора на момент начала работыfn
data
: Данные, принятые от сработавшегоtrigger
Возвращает
Subscription: Функция отмены подписки
Пример
import { createEvent, createStore } from "effector";
const foo = createEvent();
const bar = createEvent();
const store = createStore(0);
store.watch(foo, (storeValue, eventValue) => {
console.log(`triggered ${storeValue}, ${eventValue}`);
});
foo(1);
// => triggered 0, 1
bar(2);
foo(3);
// => triggered 0, 3
Документация на английском языке - самая актуальная, поскольку её пишет и обновляет команда effector. Перевод документации на другие языки осуществляется сообществом по мере наличия сил и желания.
Помните, что переведенные статьи могут быть неактуальными, поэтому для получения наиболее точной и актуальной информации рекомендуем использовать оригинальную англоязычную версию документации.