Store API (Store Unit)

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

const $store = createStore();

A Store is an object that holds the state value. The store updates when the new value is not strictly equal (!==) to the current one and is not undefined (unless the store is configured with skipVoid: false). A store is a Unit. Some stores can be derived.

What is a store anyway?

If you’re not yet familiar with how to work with a store, feel free to start here.

Store Interface

Available store methods and properties:

Method/PropertyDescription
map(fn)Creates a new derived store
on(trigger, reducer)Updates state via a reducer when the trigger is fired
watch(watcher)Calls the watcher function every time the store is updated
reset(...triggers)Resets the store to its initial state
off(trigger)Removes the subscription to the specified trigger
updates()Event that fires when the store updates
reinit()Event to reinitialize the store
shortNameID or short name of the store
defaultStateInitial state of the store
getState()Returns the current state

Immutability

A store in effector is immutable. This means that updates will only occur if the handler function (such as combine, sample, or on) returns a new object.

For example, before using array methods, you need to create a new reference to it. Here’s how to do it correctly:

$items.on(addItem, (items, newItem) => {
  const updatedItems = [...items];
  // ✅ .push method is called on a new array
  updatedItems.push(newItem);
  return updatedItems;
});

This approach should not be used, as the store will not be updated:

$items.on(addItem, (items, newItem) => {
  // ❌ Error! The array reference remains the same, the store will not be updated
  items.push(newItem);
  return items;
});

Updating objects works in a similar way.

A store in effector should be as small as possible, responsible for a specific part of the business logic, unlike, for example, Redux, whose store tends to hold everything together. When the state is atomic, the need for spreading objects becomes less frequent. However, if there is a need to frequently update deeply nested data, it is acceptable to use immer to simplify repetitive code when updating the state.

Store Methods

.map(fn)

Accepts a function fn and returns a derived store that automatically updates when the original store changes.

  • Formulae
$source.map(fn, config?);
  • Type
const $derived = $source.map<T>(
  fn: (value: SourceValue) => T,
  config?: {
    skipVoid?: boolean
  }
): Store<T>
  • Examples

Basic usage:

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");

Try it

You can pass a config object with skipVoid: false to allow the store to accept undefined:

const $titleLength = $title.map((title) => title.length, { skipVoid: false });
  • Detailed Description

The map method runs the function fn with the current store state as input every time the original store updates. The return value becomes the new state of the derived store.

  • Returns

Returns a new derived store.

.on(trigger, reducer)

Updates state using a reducer when the trigger is fired.

  • Formulae
$store.on(trigger, reducer);
  • Type
$store.on<T>(
  trigger: Unit<T> | Unit<T>[]
  reducer: (state: State, payload: T) => State | void
): this
  • Examples
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);

Try it

  • Returns

Returns the current store.

.watch(watcher)

Calls the watcher function whenever the store updates.

  • Formulae
const unwatch = $store.watch(watcher);
  • Type
$store.watch(watcher: (state: State) => any): Subscription
  • Examples
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);

Try it

  • Returns

Returns a subscription cancellation function.

.reset(...triggers)

Resets the store to its default value when any of the triggers fire.

  • Formulae
$store.reset(...triggers);
  • Type
$store.reset(...triggers: Array<Unit<any>>): this
  • Examples
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();

Try it

  • Returns

Returns the current store.

.off(trigger)

Removes the reducer for the specified trigger.

  • Formulae
$store.off(trigger);
  • Type
$store.off(trigger: Unit<any>): this
  • Examples
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);

Try it

  • Returns

Returns the current store.

Store Properties

.updates

An event that fires on every store update.

  • Examples
import { createStore, is } from "effector";

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

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

Try it

  • Returns

A derived event representing the store’s updates.

.reinit

Event to reinitialize the store to its default state.

  • Examples
import { createStore, createEvent, sample, is } from "effector";

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

const increment = createEvent();

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

Try it

  • Returns

An event that reinitializes the store.

.shortName

A string property containing the store’s ID or short name.

  • Examples
const $store = createStore(0, {
  name: "someName",
});

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

Try it

  • Returns

The store’s ID or short name.

.defaultState

The store’s default state value.

  • Example
const $store = createStore("DEFAULT");

console.log($store.defaultState === "DEFAULT"); // true
  • Returns

The default state value.

Utility Methods

.getState()

Returns the current state of the store.

Caution!

Using getState() in business logic is not recommended — it’s better to pass data through sample.

  • Examples
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());

Try it

  • Returns

The current state of the store.

Contributors