;
```
#### Properties
, which is triggered with an object of `status`, `params` and `error` or `result`:
1. `status` (*string*): A status of effect (`done` or `fail`)
2. `params` (*Params*): An argument passed to effect call
3. `error` (*Fail*): An error caught from the handler
4. `result` (*Done*): A result of the resolved handler
#### Examples
```js
import { createEffect } from "effector";
const fetchApiFx = createEffect(async ({ time, ok }) => {
await new Promise((resolve) => setTimeout(resolve, time));
if (ok) return `${time} ms`;
throw Error(`${time} ms`);
});
fetchApiFx.finally.watch((value) => {
switch (value.status) {
case "done":
console.log("Call with params", value.params, "resolved with value", value.result);
break;
case "fail":
console.log("Call with params", value.params, "rejected with error", value.error.message);
break;
}
});
await fetchApiFx({ time: 100, ok: true });
// => Call with params {time: 100, ok: true}
// resolved with value 100 ms
fetchApiFx({ time: 100, ok: false });
// => Call with params {time: 100, ok: false}
// rejected with error 100 ms
```
Try it
### `.pending` Store
Store contains `true` when effect is called but not resolved yet. Useful to show loaders.
> WARNING Important:
>
> Do not modify store value! It is derived store and should be in predictable state.
#### Formulae
```ts
effect.pending: Store;
```
* Store will update when `done` or `fail` are triggered
* Store contains `true` value until the effect is resolved or rejected
#### Returns
: Store that represents current state of the effect
#### Examples
```jsx
import React from "react";
import ReactDOM from "react-dom";
import { createEffect } from "effector";
import { useUnit } from "effector-react";
const fetchApiFx = createEffect((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
fetchApiFx.pending.watch(console.log);
const Loading = () => {
const loading = useUnit(fetchApiFx.pending);
return {loading ? "Loading..." : "Load complete"}
;
};
ReactDOM.render(, document.getElementById("root"));
fetchApiFx(3000);
```
Try it
It's property is a shorthand for common use case:
```js
import { createEffect, createStore } from "effector";
const fetchApiFx = createEffect();
// now you can use fetchApiFx.pending instead
const $isLoading = createStore(false)
.on(fetchApiFx, () => true)
.on(fetchApiFx.done, () => false)
.on(fetchApiFx.fail, () => false);
```
### `.inFlight` Store
> INFO since:
>
> [effector 20.11.0](https://changelog.effector.dev/#effector-20-11-0)
Shows how many effect calls aren't settled yet. Useful for rate limiting.
> WARNING Important:
>
> Do not modify store value! It is derived store and should be in predictable state.
#### Formulae
```ts
effect.inFlight: Store;
```
* The store will be `0` if no calls of `effect` in pending state, its default state
* On each call of `effect` state in the store will be increased
* When effect resolves to any state(done or fail) state in the store will be decreased
#### Returns
: Store that represents count of the running effects
#### Examples
```js
import { createEffect } from "effector";
const fx = createEffect(() => new Promise((rs) => setTimeout(rs, 500)));
fx.inFlight.watch((amount) => {
console.log("in-flight requests:", amount);
});
// => 0
const req1 = fx();
// => 1
const req2 = fx();
// => 2
await Promise.all([req1, req2]);
// => 1
// => 0
```
Try it
## Types
```ts
import { type EffectParams, type EffectResult, type EffectError } from "effector";
```
### `EffectParams`
Allows to extract type of Params from `effect`.
```ts
const effect: Effect;
type Params = EffectParams;
```
### `EffectResult`
Allows to extract type of result from `effect`.
```ts
const effect: Effect;
type Done = EffectResult;
```
### `EffectError`
Allows to extract type of error from `effect`.
```ts
const effect: Effect;
type Fail = EffectError;
```
# Event
```ts
import { type Event, type EventCallable } from "effector";
```
The **Event** in effector represents a user action, a step in the application process, a command to execute, or an intention to make modifications, among other things.
This unit is designed to be a carrier of information/intention/state within the application, not the holder of a state.
## `EventCallable`
### Construction
There are many ways to create an event:
* The most common createEvent
* Using Domain
* Via Event's methods and it's supertype EventCallable's methods
* Some Effect's methods return new events and readonly events
* Operators such as: createApi
#### Declaring types
Event carries some data and in a TypeScript ecosystem each data should have a defined type. When an event is explicitly created by createEvent, type of the argument must be provided as a Generic type argument:
```ts
import { createEvent } from "effector";
interface ItemAdded {
id: string;
title: string;
}
const itemAdded = createEvent();
```
In most cases, there is no reason to use `void` with another type (~~`Event`~~). Use `void` only to declare the Event or EventCallable without the argument at all. That's why it is possible to send data from an event with an argument into an event without an argument.
```ts
sample({
clock: withData, // Event
target: withoutData, // Event
});
```
We **strongly recommend** using `null` for empty values when intended:
```ts
import { createEvent } from "effector";
const maybeDataReceived = createEvent();
// maybeDataReceived: EventCallable
```
Read more in the explanation section.
### Call as function `event(argument)`
Initiates an event with the provided argument, which in turn activates any registered subscribers.
Read more in the explanation section.
#### Formulae
```ts
const event: EventCallable;
event(argument: T): T;
```
* `event` called as a function always returns its `argument` as is
* all subscribers of event receives the `argument` passed into
* when `T` is `void`, `event` can be called without arguments
* `T` by default is `void`, so generic type argument can be omitted
> WARNING Important:
>
> In Effector, any event supports only **a single argument**.
> It is not possible to call an event with two or more arguments, as in `someEvent(first, second)`.
>
> All arguments beyond the first will be ignored.
> The core team has implemented this rule for specific reasons related to the design and functionality.
#### Arguments
1. `argument` is a value of `T`. It's optional if the event is defined as `EventCallable`.
#### Throws
##### call of readonly event is not supported, use createEvent instead
> INFO since:
>
> [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0-spacewatch)
When user tried to call `Event`. In the most cases it happens when you tried to call derived event:
```ts
const numberReceived = createEvent(); // EventCallable
const stringifiedReceived = numberReceived.map((number) => String(number)); // Event
stringifiedReceived("123"); // THROWS!
```
The same for all methods returning `Event`.
To fix it create separate event via `createEvent`, and connect them by `sample`:
```ts
const numberReceived = createEvent();
const stringifiedReceived = createEvent();
sample({
clock: numberReceived,
fn: (number) => String(number),
target: stringifiedReceived,
});
stringifiedReceived("123"); // OK
```
##### unit call from pure function is not supported, use operators like sample instead
> INFO since:
>
> [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0-spacewatch)
Happens when events or effects called from pure functions, like mappers:
```ts
const someHappened = createEvent();
const another = createEvent();
const derived = someHappened.map((number) => {
another(); // THROWS!
return String(number);
});
```
To fix this, use `sample`:
```ts
const someHappened = createEvent();
const another = createEvent();
const derived = createEvent();
sample({
clock: someHappened,
target: another,
});
// The same as .map(), but using `target`
sample({
clock: someHappened,
fn: (number) => String(number),
target: derived,
});
```
#### Returns
`T`: Represents the same value that is passed into the `event`.
#### Types
```ts
import { createEvent, Event } from "effector";
const someHappened = createEvent();
// someHappened: EventCallable
someHappened(1);
const anotherHappened = createEvent();
// anotherHappened: EventCallable
anotherHappened();
```
An event can be specified with a single generic type argument. By default, this argument is set to void, indicating that the event does not accept any parameters.
### Methods
Since the `createEvent` factory creates `EventCallable` for you, its methods will be described first, even though it is a extension of the `Event` type.
All the methods and properties from Event are also available on `EventCallable` instance.
> TIP:
>
> You can think of the EventCallable and Event as type and its super type:
>
> `EventCallable extends Event`
#### `.prepend(fn)`
Creates a new `EventCallable`, that should be called, upon trigger it sends transformed data into the original event.
Works kind of like reverse `.map`. In case of `.prepend` data transforms **before the original event occurs** and in the
case of `.map`, data transforms **after original event occurred**.
If the original event belongs to some domain, then a new event will belong to it as well.
##### Formulae
```ts
const first: EventCallable;
const second: EventCallable = first.prepend(fn);
```
* When `second` event is triggered
* Call `fn` with argument from the `second` event
* Trigger `first` event with the result of `fn()`
##### Arguments
1. `fn` (*Function*): A function that receives `argument`, and should be **pure**.
##### Throws
###### unit call from pure function is not supported, use operators like sample instead
> INFO since:
>
> [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0-spacewatch)
Happens when events or effects called from pure functions, like mappers:
```ts
const someHappened = createEvent();
const another = createEvent();
const reversed = someHappened.prepend((input: number) => {
another(input); // THROWS!
return String(input);
});
```
To fix this, use `sample`:
```ts
const someHappened = createEvent();
const another = createEvent();
const reversed = createEvent();
// The same as .prepend(), but using `sample`
sample({
clock: reversed,
fn: (input) => String(input),
target: someHappened,
});
sample({
clock: reversed,
target: another,
});
```
##### Returns
EventCallable\: New event.
##### Types
There TypeScript requires explicitly setting type of the argument of `fn` function:
```ts
import { createEvent } from "effector";
const original = createEvent<{ input: string }>();
const prepended = original.prepend((input: string) => ({ input }));
// ^^^^^^ here
```
Type of the `original` event argument and the resulting type of the `fn` must be the same.
##### Examples
###### Basic
```js
import { createEvent } from "effector";
const userPropertyChanged = createEvent();
userPropertyChanged.watch(({ field, value }) => {
console.log(`User property "${field}" changed to ${value}`);
});
const changeName = userPropertyChanged.prepend((name) => ({
field: "name",
value: name,
}));
const changeRole = userPropertyChanged.prepend((role) => ({
field: "role",
value: role.toUpperCase(),
}));
changeName("john");
// => User property "name" changed to john
changeRole("admin");
// => User property "role" changed to ADMIN
changeName("alice");
// => User property "name" changed to alice
```
Try it
###### Meaningful example
You can think of this method like a wrapper function. Let's assume we have function with not ideal API, but we want to
call it frequently:
```ts
import { sendAnalytics } from "./analytics";
export function reportClick(item: string) {
const argument = { type: "click", container: { items: [arg] } };
return sendAnalytics(argument);
}
```
This is exactly how `.prepend()` works:
```ts
import { sendAnalytics } from "./analytics";
export const reportClick = sendAnalytics.prepend((item: string) => {
return { type: "click", container: { items: [arg] } };
});
reportClick("example");
// reportClick triggered "example"
// sendAnalytics triggered { type: "click", container: { items: ["example"] } }
```
Check all other methods on Event.
## `Event`
A **Event** is a super type of `EventCallable` with different approach. Firstly, invoking a Event is not
allowed, and it cannot be used as a `target` in the `sample` operator, and so on.
The primary purpose of a Event is to be triggered by internal code withing the effector library or ecosystem.
For instance, the `.map()` method returns a Event, which is subsequently called by the `.map()` method itself.
> INFO:
>
> There is no need for user code to directly invoke such an Event.
>
> If you find yourself needing to call a Event, it may be necessary to reevaluate and restructure your
> application's logic.
All the functionalities provided by an Event are also supported in an EventCallable.
### Construction
There is no way to manually create Event, but some methods and operators returns derived events, they are return
`Event` type:
* Event's methods like: .map(fn), .filter({fn}), and so on
* Store's property: '.updates'
* Effect's methods and properties
* operators like: sample, merge
### Throws
* **Errors related to incorrect usage**: More details in specific method sections.
### Declaring types
It becomes necessary in cases where a factory or library requires an event to subscribe to its updates, ensuring proper
integration and interaction with the provided functionality:
```ts
const event: Event;
```
### Methods
#### `.map(fn)`
Creates a new derived Event, which will be called after the original event is called, using the result of the fn
function as its argument. This special function enables you to break down and manage data flow, as well as extract or
transform data within your business logic model.
##### Formulae
```ts
const first: Event | EventCallable;
const second: Event = first.map(fn);
```
* When `first` is triggered, pass payload from `first` to `fn`.
* Trigger `second` with the result of the `fn()` call as payload.
* The function `fn` is invoked each time the `first` event is triggered.
* Also, the `second` event triggered each time the `first` is triggered.
##### Arguments
1. `fn` (*Function*): A function that receives `argument`, and should be .
##### Throws
###### unit call from pure function is not supported, use operators like sample instead
> INFO since:
>
> [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0-spacewatch)
Happens when events or effects called from pure functions, like mappers:
```ts
const someHappened = createEvent();
const another = createEvent();
const derived = someHappened.map((number) => {
another(); // THROWS!
return String(number);
});
```
To fix this, use `sample`:
```ts
const someHappened = createEvent();
const another = createEvent();
const derived = createEvent();
sample({
clock: someHappened,
target: another,
});
// The same as .map(), but using `target`
sample({
clock: someHappened,
fn: (number) => String(number),
target: derived,
});
```
##### Returns
Event\: The new event.
##### Types
The resulting type of the `fn` function will be utilized to define the type of the derived event.
```ts
import { createEvent } from "effector";
const first = createEvent();
// first: Event
const second = first.map((count) => count.toString());
// second: Event
```
The `first` event can be represented as either `Event` or `EventCallable`.
The `second` event will always be represented as `Event`.
##### Examples
```js
import { createEvent } from "effector";
const userUpdated = createEvent();
// you may decompose dataflow with .map() method
const userNameUpdated = userUpdated.map(({ user }) => name);
// either way you can transform data
const userRoleUpdated = userUpdated.map((user) => user.role.toUpperCase());
userNameUpdated.watch((name) => console.log(`User's name is [${name}] now`));
userRoleUpdated.watch((role) => console.log(`User's role is [${role}] now`));
userUpdated({ name: "john", role: "admin" });
// => User's name is [john] now
// => User's role is [ADMIN] now
```
Try it
#### `.filter({ fn })`
This method generates a new derived Event that will be invoked after the original event, but only if the `fn`
function returns `true`. This special function enables you to break down data flow into a branches and
subscribe on them within the business logic model.
> TIP:
>
> sample operator with `filter` argument is the preferred filtering method.
##### Formulae
```ts
const first: Event | EventCallable;
const second: Event = first.filter({ fn });
```
* When `first` is triggered, pass payload from `first` to `fn`.
* The `second` event will be triggered only if `fn` returns `true`, with the argument from `first` event.
* The function `fn` is invoked each time the `first` event is triggered.
* Also, the `second` event triggered each time the `first` is triggered, **and** the `fn` returned `true`.
##### Arguments
1. `fn` (*Function*): A function that receives `argument`, and should be .
> INFO Note:
>
> Here, due to legacy restrictions `fn` is required to use object form because `event.filter(fn)` was an alias
> for Event filterMap.
>
> Use it always like this `.filter({ fn })`.
##### Throws
###### unit call from pure function is not supported, use operators like sample instead
> INFO since:
>
> [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0-spacewatch)
Happens when events or effects called from pure functions, like guards:
```ts
const countReceived = createEvent();
const eachReceived = createEvent();
const receivedEven = someHappened.filter({
fn(count) {
eachReceived(count); // THROWS!
return count % 2 === 0;
},
});
```
To fix this, use `sample` to call `eachReceived`:
```ts
const countReceived = createEvent();
const eachReceived = createEvent();
const receivedEven = someHappened.filter({
fn(count) {
return count % 2 === 0;
},
});
sample({
clock: someHappened,
target: eachReceived,
});
```
##### Returns
Event\: The new event
##### Types
Method `.filter()` always returns Event. Also this event will have the same type as the original type:
```ts
import { createEvent } from "effector";
const numberReceived = createEvent();
// numberReceived: Event
const evenReceived = numberReceived.filter({
fn: (number) => number % 2 === 0,
});
// evenReceived: Event
evenReceived.watch(console.info);
numberReceived(5); // nothing
numberReceived(2); // => 2
```
##### Examples
```js
import { createEvent, createStore } from "effector";
const numbers = createEvent();
const positiveNumbers = numbers.filter({
fn: ({ x }) => x > 0,
});
const $lastPositive = createStore(0).on(positiveNumbers, (n, { x }) => x);
$lastPositive.watch((x) => {
console.log("last positive:", x);
});
// => last positive: 0
numbers({ x: 0 });
// no reaction
numbers({ x: -10 });
// no reaction
numbers({ x: 10 });
// => last positive: 10
```
Try it
##### Meaningful example
Let's assume a standard situation when you want to buy sneakers in the shop, but there is no size. You subscribe to the
particular size of the sneakers' model, and in addition, you want to receive a notification if they have it, and ignore
any other notification. Therefore, filtering can be helpful for that. Event filtering works in the same way. If `filter`
returns `true`, the event will be called.
```ts
const sneackersReceived = createEvent();
const uniqueSizeReceived = sneackersReceived.filter({
fn: (sneackers) => sneackers.size === 48,
});
```
#### `.filterMap(fn)`
> INFO since:
>
> [effector 20.0.0](https://changelog.effector.dev/#effector-20-0-0)
This methods generates a new derived Event that **may be invoked** after the original event, but with the
transformed argument. This special method enabled you to simultaneously transform data and filter out trigger of the
event.
This method looks like the `.filter()` and `.map()` merged in the one. That's it. The reason for creating was an
impossibility for event filtering.
This method is mostly useful with JavaScript APIs whose returns `undefined` sometimes.
##### Formulae
```ts
const first: Event | EventCallable;
const second: Event = first.filterMap(fn);
```
* When `first` is triggered, call `fn` with payload from `first`
* If `fn()` returned `undefined` do not trigger `second`
* If `fn()` returned some data, trigger `second` with data from `fn()`
##### Arguments
1. `fn` (*Function*): A function that receives `argument`, should be .
The `fn` function should return some data. When `undefined` is returned, the update of derived event will be skipped.
##### Throws
###### unit call from pure function is not supported, use operators like sample instead
> INFO since:
>
> [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0-spacewatch)
Happens when events or effects called from pure functions, like mappers:
```ts
const countReceived = createEvent();
const eachReceived = createEvent();
const receivedEven = someHappened.filterMap((count) => {
eachReceived(count); // THROWS!
return count % 2 === 0 ? Math.abs(count) : undefined;
});
```
To fix this, use `sample` to call `eachReceived`:
```ts
const countReceived = createEvent();
const eachReceived = createEvent();
const receivedEven = someHappened.filterMap((count) => {
return count % 2 === 0 ? Math.abs(count) : undefined;
});
sample({
clock: someHappened,
target: eachReceived,
});
```
##### Returns
Event\: The new event
##### Types
The type for the derived event is automatically inferred from the `fn` declaration.
No need to explicitly set type for variable or generic type argument:
```ts
import { createEvent } from "effector";
const first = createEvent();
// first: Event
const second = first.filterMap((count) => {
if (count === 0) return;
return count.toString();
});
// second: Event
```
The `first` event can be represented as either `Event` or `EventCallable`.
The `second` event will always be represented as `Event`.
##### Examples
```tsx
import { createEvent } from "effector";
const listReceived = createEvent();
// Array.prototype.find() returns `undefined` when no item is found
const effectorFound = listReceived.filterMap((list) => list.find((name) => name === "effector"));
effectorFound.watch((name) => console.info("found", name));
listReceived(["redux", "effector", "mobx"]); // => found effector
listReceived(["redux", "mobx"]);
```
Try it
##### Meaningful example
Consider a scenario where you walk into a grocery store with a specific task: you need to purchase 10 apples, but only
if they're red. If they're not red, you're out of luck.
Let's consider by steps:
1. Take one apple;
2. Have a look, is it red(put in a pack) or not(take another).
And you repeat this until you complete the task. Now think about it in the effector terms, and we consider the positive
case:
1. Take an apple β event;
2. Have a look, red or no β filter;
3. You keep it β map;
4. Put in pack β event.
5. Pack β store
#### `.watch(watcher)`
This method enables you to call callback on each event trigger with the argument of the event.
> TIP Keep in mind:
>
> The `watch` method neither handles nor reports exceptions, manages the completion of asynchronous operations, nor
> addresses data race issues.
>
> Its primary intended use is for short-term debugging and logging purposes.
Read more in the explanation section.
##### Formulae
```ts
const event: Event | EventCallable;
const unwatch: () => void = event.watch(fn);
```
* The `fn` will be called on each `event` trigger, passed argument of the `event` to the `fn`.
* When `unwatch` is called, stop calling `fn` on each `event` trigger.
##### Arguments
1. `watcher` (): A function that receives `argument` from the event.
##### Returns
: Unsubscribe function.
##### Examples
```js
import { createEvent } from "effector";
const sayHi = createEvent();
const unwatch = sayHi.watch((name) => console.log(`${name}, hi there!`));
sayHi("Peter"); // => Peter, hi there!
unwatch();
sayHi("Drew"); // => nothing happened
```
Try it
#### `.subscribe(observer)`
This is the low-level method to integrate event with the standard `Observable` pattern.
> TIP Keep in mind:
>
> You don't need to use this method on your own. It is used under the hood by rendering engines or so on.
Read more:
* https://rxjs.dev/guide/observable
* https://github.com/tc39/proposal-observable
### Properties
These set of property is mostly set by effector/babel-plugin
or @effector/swc-plugin. So they are exist only when babel or SWC is used.
#### `.sid`
It is an unique identifier for each event.
It is important to note, SID is not changes on each app start, it is statically written inside your app bundle to
absolutely identify units.
It can be useful to send events between workers or
server/browser: [examples/worker-rpc](https://github.com/effector/effector/tree/master/examples/worker-rpc).
It has the `string | null` type.
#### `.shortName`
It is a `string` type property, contains the name of the variable event declared at.
```ts
import { createEvent } from "effector";
const demo = createEvent();
// demo.shortName === 'demo'
```
But reassign event to another variable changes nothing:
```ts
const another = demo;
// another.shortName === 'demo'
```
#### `.compositeName`
This property contains the full internal chain of units. For example, event can be created by the domain, so the
composite name will contain a domain name inside it.
> TIP Keep in mind:
>
> Usually, if long name is needed, is better to pass it explicitly to `name` field
```ts
import { createEvent, createDomain } from "effector";
const first = createEvent();
const domain = createDomain();
const second = domain.createEvent();
console.log(first.compositeName);
// => { shortName: "first", fullName: "first", path: ["first"] }
console.log(second.compositeName);
// => { shortName: "second", fullName: "domain/second", path: ["domain", "second"] }
```
## Types
```ts
import { type EventPayload } from "effector";
```
### `EventPayload`
Extracts type of payload from `Event` or `EventCallable`.
```ts
const event: Event;
type Payload = EventPayload;
```
# Scope
```ts
import { type Scope } from "effector";
```
`Scope` is a fully isolated instance of application.
The primary purpose of scope includes SSR (Server-Side Rendering) but is not limited to this use case. A `Scope` contains an independent clone of all units (including connections between them) and basic methods to access them.
A `Scope` can be created using fork.
### Imperative effects calls with scope
When making imperative effect calls within effect handlers, it is supported but **not** within `watch` functions. For effect handlers that call other effects, ensure to only call effects, not common asynchronous functions. Furthermore, effect calls should be awaited:
**β
Correct usage for an effect without inner effects:**
```js
const delayFx = createEffect(async () => {
await new Promise((resolve) => setTimeout(resolve, 80));
});
```
**β
Correct usage for an effect with inner effects:**
```js
const authUserFx = createEffect();
const sendMessageFx = createEffect();
const sendWithAuthFx = createEffect(async () => {
await authUserFx();
await delayFx();
await sendMessageFx();
});
```
**β Incorrect usage for an effect with inner effects:**
```js
const sendWithAuthFx = createEffect(async () => {
await authUserFx();
// Incorrect! This should be wrapped in an effect.
await new Promise((resolve) => setTimeout(resolve, 80));
// Context is lost here.
await sendMessageFx();
});
```
For scenarios where an effect might call another effect or perform asynchronous computations, but not both, consider utilizing the attach method instead for more succinct imperative calls.
### Loss of `scope`
**What are the risks of calling effects after asynchronous functions?** The state in which the application enters after such a call is called "loss of scope." This means that after completing the call of a regular asynchronous function, all subsequent actions will fall into the global mode (this is what works with a direct call to `$store.getState()`), meaning all data updates will **not** enter the scope in which the work was conducted. As a result, an inconsistent state will be sent to the client.
Imperative calls of effects are safe in this regard because effector remembers the scope in which the imperative call of the effect began and restores it after the call, allowing for another call in sequence.
You can call methods like `Promise.all([fx1(), fx2()])` and others from the standard JavaScript API because in these cases, the calls to effects still happen synchronously, and the scope is safely preserved.
All rules discussed for effects also apply to imperative calls of events.
**How to circumvent this limitation?** There are situations where calls outside the scope cannot be avoided; typical examples are `setInterval` and `history.listen`. To safely pass an effect (or event) to these functions, you can use the method scopeBind. It creates a function bound to the scope in which the method was called, allowing it to be safely called later.
```js
const sendWithAuthFx = createEffect(async () => {
// Now this function can be called safely
// without adhering to the scope loss rules
const sendMessage = scopeBind(sendMessageFx);
await authUserFx();
// There is no context inside setInterval, but our function is bound
return setInterval(sendMessage, 500);
});
```
> TIP Keep in mind:
>
> Remember to clear setInterval after finishing work with the scope to avoid memory leaks. You can clear setInterval with a separate effect by first returning its id from the first effect and storing it in a separate store.
**Is there any way to circumvent the loss of scope? Is this an issue specific to effector?** This is a general principle of working with asynchrony in JavaScript. All technologies that face the need to maintain the context in which calls occur handle this difficulty in one way or another. The most prominent example is [zone.js](https://github.com/angular/angular/tree/main/packages/zone.js), which wraps all asynchronous global functions like `setTimeout` or `Promise.resolve` to maintain the context. Other solutions to this problem include using generators or `ctx.schedule(() => asyncCall())`.
**Will there be a universal solution to the context loss problem?** Yes. A new proposal in the language called [async context](https://github.com/tc39/proposal-async-context) aims to solve this problem once and for all. It will allow asynchronous logic to be run once, retrieving data from the context in all related calls, regardless of how they occur. Once the proposal is incorporated into the language and gains broad support, effector will definitely switch to this solution, and the rules for calling effects will become a thing of the past.
## Methods
### `.getState($store)`
Returns the value of a store in a given `Scope`.
#### Formulae
```ts
const scope: Scope;
const $value: Store | StoreWritable;
const value: T = scope.getState($value);
```
#### Returns
`T` the value of the store
#### Examples
Create two instances of an application, trigger events in them, and test the `$counter` store value in both instances:
```js
import { createStore, createEvent, fork, allSettled } from "effector";
const inc = createEvent();
const dec = createEvent();
const $counter = createStore(0);
$counter.on(inc, (value) => value + 1);
$counter.on(dec, (value) => value - 1);
const scopeA = fork();
const scopeB = fork();
await allSettled(inc, { scope: scopeA });
await allSettled(dec, { scope: scopeB });
console.log($counter.getState()); // => 0
console.log(scopeA.getState($counter)); // => 1
console.log(scopeB.getState($counter)); // => -1
```
Try it
# Store
```ts
import { type Store, type StoreWritable } from "effector";
```
*Store* is an object that holds the state value. Store gets updates when it receives a value that is not equal (`!==`) to the current one and to `undefined`. Store is a Unit. Some stores can be derived.
### 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:
```ts
$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**:
```ts
$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](https://immerjs.github.io/immer/produce) to simplify repetitive code when updating the state.
## Store Methods
### `.map(fn)`
Creates a derived store. It will call a provided function with the state when the original store updates, and will use the result to update the derived store.
#### Formulae
```ts
const $second = $first.map(fn);
```
#### Arguments
1. `fn` (*Function*): Function that receives `state` and returns a new state for the derived store.
2. `config` (*Object*): Optional configuration.
#### Returns
: New derived store.
#### Examples
##### Basic
```js
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("new length", length);
});
changed("hello");
changed("world");
changed("hello world");
```
Try it
##### SkipVoid
```js
const $length = $title.map((title) => title.length, { skipVoid: false });
```
### `.on(trigger, reducer)`
Updates state when `trigger` is triggered by using a reducer.
#### Formulae
```ts
$store.on(trigger, reducer);
```
#### Arguments
1. `trigger`: *Event*, *Effect*, or another *Store*.
2. `reducer`: *Reducer*: Function that receives `state` and `params` and returns a new state.
#### Returns
: Current store.
#### Examples
##### Basic
```js
import { createEvent, createStore } from "effector";
const $store = createStore(0);
const changed = createEvent();
$store.on(changed, (value, incrementor) => value + incrementor);
$store.watch((value) => {
console.log("updated", value);
});
changed(2);
changed(2);
```
Try it
### `.watch(watcher)`
Calls `watcher` function each time when the store is updated.
#### Formulae
```ts
const unwatch = $store.watch(watcher);
```
#### Arguments
1. `watcher`: : Watcher function that receives the current store state as the first argument.
#### Returns
: Unsubscribe function.
#### Examples
##### Basic
```js
import { createEvent, createStore } from "effector";
const add = createEvent();
const $store = createStore(0).on(add, (state, payload) => state + payload);
$store.watch((value) => console.log(`current value: ${value}`));
add(4);
add(3);
```
Try it
### `.reset(...triggers)`
Resets store state to the default value.
#### Formulae
```ts
$store.reset(...triggers);
```
#### Arguments
1. `triggers`: (*(Event | Effect | Store)\[]*): any number of *Events*, *Effects*, or *Stores*.
#### Returns
: Current store.
#### Examples
##### Basic
```js
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
### `.off(trigger)`
Removes reducer for the given `trigger`.
#### Formulae
```ts
$store.off(trigger);
```
#### Arguments
1. `trigger`: *Event*, *Effect*, or *Store*.
#### Returns
: Current store.
#### Examples
##### Basic
```js
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
## Store Properties
### `.updates`
#### Returns
: Event that represents updates of the given store.
#### Example
```js
import { createStore, is } from "effector";
const $clicksAmount = createStore(0);
is.event($clicksAmount.updates); // true
$clicksAmount.updates.watch((amount) => {
console.log(amount);
});
```
Try it
### `.reinit`
#### Returns
: Event that can reinitialize a store with a default value.
#### Example
```js
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
### `.shortName`
#### Returns
(*`string`*): ID or short name of the store.
### `.defaultState`
#### Returns
(*`State`*): Default state of the store.
#### Example
```ts
const $store = createStore("DEFAULT");
console.log($store.defaultState === "DEFAULT");
```
## Utility methods
### `.getState()`
Returns the current state of the store.
#### Returns
(*`State`*): Current state of the store.
#### Example
```js
import { createEvent, createStore } from "effector";
const add = createEvent();
const $number = createStore(0).on(add, (state, data) => state + data);
add(2);
add(3);
console.log($number.getState());
```
Try it
## Readonly store
TBD
## Types
```ts
import { type StoreValue } from "effector";
```
### `StoreValue`
Extracts type of `Store` or `StoreWritable` value.
```ts
const $store: Store;
type Value = StoreValue;
```
# allSettled
## Methods
### `allSettled(unit, {scope, params?})`
Calls the provided unit within the current scope and wait for all triggered effects to complete.
#### Formulae
```ts
allSettled(unit: Event, {scope: Scope, params?: T}): Promise
allSettled(unit: Effect, {scope: Scope, params?: T}): Promise<
| {status: 'done'; value: Done}
| {status: 'fail'; value: Fail}
>
allSettled(unit: Store, {scope: Scope, params?: T}): Promise
```
#### Arguments
1. `unit`: or to be called
2. `scope`:
3. `params`: params passed to `unit`
> INFO since:
>
> Return value for effect is supported since [effector 21.4.0](https://changelog.effector.dev/#effector-21-4-0)
#### Examples
> TIP Contribution:
>
> TBD
>
> Please, [open PullRequest](https://github.com/effector/effector) and contribute examples for this section via "Edit this page" link below.
### `allSettled(scope)`
Checks the provided scope for any ongoing computations and wait for their completion.
#### Formulae
```ts
allSettled(scope): Promise
```
#### Arguments
1. `scope`:
> INFO since:
>
> Supported since effector 22.5.0
#### Examples
##### Usage in tests
For example, tests that validate the integration with an external reactive API
```ts
import {createEvent, sample, fork, scopeBind, allSettled} from 'effector'
test('integration with externalSource', async () => {
const scope = fork()
const updated = createEvent()
sample({
clock: updated,
target: someOtherLogicStart,
})
// 1. Subscribe event to external source
const externalUpdated = scopeBind(updated, {scope})
externalSource.listen(() => externalUpdates())
// 2. Trigger update of external source
externalSource.trigger()
// 3. Wait for all triggered computations in effector's scope, even though these were not triggered by effector itself
await allSettled(scope)
// 4. Check anything as usual
expect(...).toBe(...)
})
```
# attach
```ts
import { attach } from "effector";
```
> INFO since:
>
> Available since [effector 20.13.0](https://changelog.effector.dev/#effector-20-13-0).
>
> Since [effector 22.4.0](https://changelog.effector.dev/#effector-encke-22-4-0), it is available to check whether effect is created via `attach` method β is.attached.
Creates new effects based on the other effects, stores. Allows mapping params and handling errors.
Use cases: declarative way to pass values from stores to effects and argument preprocessing. Most useful case is `attach({ source, async effect })`.
> TIP:
>
> The attached effects are the same first-class citizens as the regular effects made by createEffect. You should place them in the same files as regular effects, also you can use the same naming strategy.
## Methods
### `attach({effect})`
> INFO since:
>
> [effector 21.5.0](https://changelog.effector.dev/#effector-21-5-0)
Create effect which will call `effect` with params as it is. That allows creating separate effects with shared behavior.
#### Formulae
```ts
const attachedFx = attach({ effect: originalFx });
```
* When `attachedFx` is triggered, then `originalFx` is triggered too
* When `originalFx` is finished (fail/done), then `attachedFx` must be finished with the same state.
#### Arguments
* `effect` (): Wrapped effect
#### Returns
: New effect
#### Types
```ts
const originalFx: Effect;
const attachedFx: Effect = attach({
effect: originalFx,
});
```
In case of this simple variant of `attach`, types of `originalFx` and `attachedFx` will be the same.
#### Examples
It allows to create *local* copy of the effect, to react only on triggers emitted from the current *local* code.
```ts
import { createEffect, attach } from "effector";
const originalFx = createEffect((word: string) => {
console.info("Printed:", word);
});
const attachedFx = attach({ effect: originalFx });
originalFx.watch(() => console.log("originalFx"));
originalFx.done.watch(() => console.log("originalFx.done"));
attachedFx.watch(() => console.log("attachedFx"));
attachedFx.done.watch(() => console.log("attachedFx.done"));
originalFx("first");
// => originalFx
// => Printed: first
// => originalFx.done
attachedFx("second");
// => attachedFx
// => originalFx
// Printed: second
// => originalFx.done
// => attachedFx.done
```
Try it
### `attach({source, effect})`
Create effect which will trigger given one with values from `source` stores.
#### Formulae
```ts
const attachedFx = attach({
source,
effect: originalFx,
});
```
* When `attachedFx` is triggered, read data from `source`, trigger with the data `originalFx`
* When `originalFx` is finished, pass the same resolution (done/fail) into `attachedFx` and finish it
#### Arguments
* `source` ( | `{[key: string]: Store}`): Store or object with stores, values of which will be passed to the second argument of `mapParams`
* `effect` (): Original effect
#### Returns
: New effect
#### Types
> TIP:
>
> You don't need to explicitly set types for each declaration. The purpose of the following example is to provide a clear understanding.
In most userland code you will write code like this, without explicit types of the `let`/`const`:
```ts
const originalFx = createEffect(async () => {});
const $store = createStore(initialValue);
const attachedFx = attach({
source: $store,
effect: originalFx,
});
```
##### Single store
```ts
const originalFx: Effect;
const $store: Store;
const attachedFx: Effect = attach({
source: $store,
effect: originalFx,
});
```
[Try it in ts playground](https://tsplay.dev/NBJDDN)
Types of the `source` store and `effect` params must be the same.
But the `attachedFx` will omit the type of params, it means the attached effect not requires any params at all.
##### Shape of stores
```ts
const originalFx: Effect<{ a: A; b: B }, Done, Fail>;
const $a: Store;
const $b: Store;
const attachedFx: Effect = attach({
source: { a: $a, b: $b },
effect: originalFx,
});
```
[Try it in ts playground](https://tsplay.dev/mbE58N)
Types of the `source` object must be the same as `originalFx` params. But the `attachedFx` will omit the type of params, it means the attached effect not requires any params at all.
#### Examples
```ts
import { createEffect, createStore, attach } from "effector";
const requestPageFx = createEffect<{ page: number; size: number }, string[]>(
async ({ page, size }) => {
console.log("Requested", page);
return page * size;
},
);
const $page = createStore(1);
const $size = createStore(20);
const requestNextPageFx = attach({
source: { page: $page, size: $size },
effect: requestPageFx,
});
$page.on(requestNextPageFx.done, (page) => page + 1);
requestPageFx.doneData.watch((position) => console.log("requestPageFx.doneData", position));
await requestNextPageFx();
// => Requested 1
// => requestPageFx.doneData 20
await requestNextPageFx();
// => Requested 2
// => requestPageFx.doneData 40
await requestNextPageFx();
// => Requested 3
// => requestPageFx.doneData 60
```
Try it
### `attach({source, async effect})`
> INFO since:
>
> [effector 22.0.0](https://changelog.effector.dev/#effector-22-0-0)
Creates effect which will call async function with values from the `source` stores.
#### Formulae
```ts
const attachedFx = attach({
source,
async effect(source, params) {},
});
```
* When `attachedFx` is triggered, read data from the `source`, call `effect` function.
* When `effect` function returns resolved `Promise`, finish `attachedFx` with the data from the function as `attachedFx.done`.
* When `effect` throws exception, or returns rejected `Promise`, finish `attachedFx` with the data from function as `attachedFx.fail`.
#### Arguments
* `effect` (*Function*): `(source: Source, params: Params) => Promise | Result`
* `source` ( | `{[key: string]: Store}`): Store or object with stores, values of which will be passed to the first argument of `effect`
#### Returns
: New effect
#### Usage with scope
Any effects called inside `async effect` function will propagate scope.
```ts
const outerFx = createEffect((count: number) => {
console.log("Hit", count);
});
const $store = createStore(0);
const attachedFx = attach({
source: $store,
async effect(count, _: void) {},
});
```
**Scope is lost** if there are any asynchronous function calls made:
```ts
const attachedFx = attach({
source: $store,
async effect(source) {
// Here is ok, the effect is called
const resultA = await anotherFx();
// Be careful:
const resultB = await regularFunction();
// Here scope is lost.
},
});
```
To solve this case, you need to just wrap your `regularFunction` into effect:
```ts
const regularFunctionFx = createEffect(regularFunction);
```
#### Types
##### Single store
```ts
const $store: Store;
const attachedFx: Effect = attach({
source: $store,
async effect(source, params: Params): Done | Promise {},
});
```
You need to type explicitly only `params` argument. All other types of arguments should be inferred automatically. Also, you may want to explicitly set the return type of the `effect` function.
If you want to remove any arguments from the `attachedFx` you need to just remove second argument from `effect` function:
```ts
const attachedFx: Effect = attach({
source: $store,
async effect(source) {},
});
```
##### Multiple stores
> TIP:
>
> For details review previous section of types. Here the same logic.
```ts
// Userland example, without explicit type declarations
const $foo = createStore(100);
const $bar = createStore("demo");
const attachedFx = attach({
source: { foo: $foo, bar: $bar },
async effect({ foo, bar }, { baz }: { baz: boolean }) {
console.log("Hit!", { foo, bar, baz });
},
});
attachedFx({ baz: true });
// => Hit! { foo: 100, bar: "demo", baz: true }
```
[Try it in ts playground](https://tsplay.dev/m3xjbW)
#### Example
> WARNING TBD:
>
> Please, open pull request via "Edit this page" link.
### `attach({effect, mapParams})`
Creates effect which will trigger given one by transforming params by `mapParams` function.
#### Formulae
```ts
const attachedFx = attach({
effect: originalFx,
mapParams,
});
```
* When `attachedFx` triggered, payload passed into `mapParams` function, then the result of it passed into `originalFx`
* When `originalFx` is finished, then `attachedFx` must be finished with the same resolution (done/fail).
* If `mapParams` throws an exception, then `attachedFx` must be finished with the error as `attachedFx.fail`. But `originalFx` will not be triggered at all.
#### Arguments
* `effect` (): Wrapped effect
* `mapParams` (`(newParams) => effectParams`): Function which receives new params and maps them to the params of the wrapped `effect`. Works mostly like event.prepend. Errors happened in `mapParams` function will force attached effect to fail.
#### Returns
: New effect
#### Types
```ts
const originalFx: Effect;
const attachedFx: Effect = attach({
effect: originalFx,
mapParams: (params: B): A {},
});
```
`mapParams` must return the same type `originalFx` receives as params.
If `attachedFx` must be called without any arguments, then `params` can be safely removed from the `mapParams`:
```ts
const attachedFx: Effect = attach({
effect: originalFx,
mapParams: (): A {},
});
```
[Try it in ts playground](https://tsplay.dev/wXOYoW)
But if `mapParams` function throws an exception, it is on your own to check types compatibility, because of TypeScript.
```ts
const attachedFx: Effect = attach({
effect: originalFx,
mapParams: (): A {
throw new AnyNonFailType(); // It can be noncompatible with `Fail` type
},
});
```
#### Examples
##### Map arguments
```ts
import { createEffect, attach } from "effector";
const originalFx = createEffect((a: { input: number }) => a);
const attachedFx = attach({
effect: originalFx,
mapParams(a: number) {
return { input: a * 100 };
},
});
originalFx.watch((params) => console.log("originalFx started", params));
attachedFx(1);
// => originalFx { input: 100 }
```
Try it
##### Handle exceptions
```ts
import { createEffect, attach } from "effector";
const originalFx = createEffect((a: { a: number }) => a);
const attachedFx = attach({
effect: originalFx,
mapParams(a: number) {
throw new Error("custom error");
return { a };
},
});
attachedFx.failData.watch((error) => console.log("attachedFx.failData", error));
attachedFx(1);
// => attachedFx.failData
// => Error: custom error
```
Try it
### `attach({source, mapParams, effect})`
Creates effect which will read values from `source` stores, pass them with params to `mapParams` function and then call `effect` with the result.
#### Formulae
> TIP Note:
>
> This variant of `attach` mostly works like the attach({effect, mapParams}). The same things are omitted from this section.
```ts
const attachedFx = attach({
source,
mapParams,
effect: originalFx,
});
```
* When `attachedFx` triggered, payload passed into `mapParams` function with value from `source` store, then the result of it passed into `originalFx`
* When `originalFx` is finished, then `attachedFx` must be finished with the same resolution (done/fail).
* If `mapParams` throws an exception, then `attachedFx` must be finished with the error as `attachedFx.fail`. But `originalFx` will not be triggered at all.
#### Arguments
* `source` ( | `{[key: string]: Store}`): Store or object with stores, values of which will be passed to the second argument of `mapParams`
* `mapParams` (`(newParams, values) => effectParams`): Function which receives new params and current value of `source` and combines them to the params of the wrapped `effect`. Errors happened in `mapParams` function will force attached effect to fail
* `effect` (): Wrapped effect
#### Returns
: New effect
#### Types
> WARNING TBD:
>
> Please, open pull request via "Edit this page" link.
#### Examples
##### With factory
```ts
// ./api/request.ts
import { createEffect, createStore } from "effector";
export const backendRequestFx = createEffect(async ({ token, data, resource }) => {
return fetch(`https://example.com/api${resource}`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(data),
});
});
export const $requestsSent = createStore(0);
$requestsSent.on(backendRequestFx, (total) => total + 1);
```
```ts
// ./api/authorized.ts
import { attach, createStore } from "effector";
const $token = createStore("guest_token");
export const authorizedRequestFx = attach({
effect: backendRequestFx,
source: $token,
mapParams: ({ data, resource }, token) => ({ data, resource, token }),
});
export function createRequest(resource) {
return attach({
effect: authorizedRequestFx,
mapParams: (data) => ({ data, resource }),
});
}
```
```ts
// ./api/index.ts
import { createRequest } from "./authorized";
import { $requestsSent } from "./request";
const getUserFx = createRequest("/user");
const getPostsFx = createRequest("/posts");
$requestsSent.watch((total) => {
console.log(`client analytics: sent ${total} requests`);
});
const user = await getUserFx({ name: "alice" });
/*
POST https://example.com/api/user
{"name": "alice"}
Authorization: Bearer guest_token
*/
// => client analytics: sent 1 requests
const posts = await getPostsFx({ user: user.id });
/*
POST https://example.com/api/posts
{"user": 18329}
Authorization: Bearer guest_token
*/
// => client analytics: sent 2 requests
```
To allow factory works correct, add a path to a `./api/authorized` into `factories` option for Babel plugin:
```json5
// .babelrc
{
plugins: [
[
"effector/babel-plugin",
{
factories: ["src/path-to-your-entity/api/authorized"],
},
],
],
}
```
### Parameters
`attach()` also receives extra parameters, you can use it when you need.
#### `name`
```ts
attach({ name: string });
```
It allows us to explicitly set the name of the created attached effect:
```ts
import { attach } from "effector";
const attachedFx = attach({
name: "anotherUsefulName",
source: $store,
async effect(source, params: Type) {
// ...
},
});
attachedFx.shortName; // "anotherUsefulName"
```
This parameter exists in **any variant** of the `attach`.
#### `domain`
```ts
attach({ domain: Domain });
```
It allows to create effect inside specified domain.
> Note: this property can only be used with a plain function `effect`.
```ts
import { createDomain, createStore, attach } from "effector";
const reportErrors = createDomain();
const $counter = createStore(0);
const attachedFx = attach({
domain: reportErrors,
source: $counter,
async effect(counter) {
// ...
},
});
```
# Babel plugin
Built-in plugin for babel can be used for ssr and debugging. It inserts a name a Unit,
inferred from variable name and `sid` (Stable IDentifier), computed from the location in the source code.
For example, in case effects without handlers, it improves error messages by
clearly showing in which effect error happened.
```js
import { createEffect } from "effector";
const fetchFx = createEffect();
fetchFx();
// => no handler used in fetchFx
```
Try it
## Usage
In the simplest case, it can be used without any configuration:
```json
// .babelrc
{
"plugins": ["effector/babel-plugin"]
}
```
## SID
> INFO since:
>
> [effector 20.2.0](https://changelog.effector.dev/#effector-20-2-0)
Stable hash identifier for events, effects, stores and domains, preserved between environments, to handle client-server
interaction within the same codebase.
The crucial value of sid is that it can be autogenerated by `effector/babel-plugin` with default config, and it will be stable between builds.
> TIP Deep dive explanation:
>
> If you need the detailed deep-dive explanation about why we need SIDs and how they are used internally, you can find it by following this link
See [example project](https://github.com/effector/effector/tree/master/examples/worker-rpc)
```js
// common.js
import { createEffect } from "effector";
export const getUser = createEffect({ sid: "GET /user" });
console.log(getUsers.sid);
// => GET /user
```
```js
// worker.js
import { getUsers } from "./common.js";
getUsers.use((userID) => fetch(userID));
getUsers.done.watch(({ result }) => {
postMessage({ sid: getUsers.sid, result });
});
onmessage = async ({ data }) => {
if (data.sid !== getUsers.sid) return;
getUsers(data.userID);
};
```
```js
// client.js
import { createEvent } from "effector";
import { getUsers } from "./common.js";
const onMessage = createEvent();
const worker = new Worker("worker.js");
worker.onmessage = onMessage;
getUsers.use(
(userID) =>
new Promise((rs) => {
worker.postMessage({ sid: getUsers.sid, userID });
const unwatch = onMessage.watch(({ data }) => {
if (data.sid !== getUsers.sid) return;
unwatch();
rs(data.result);
});
}),
);
```
## Configuration
### `importName`
Specifying import name or names to process by plugin. Import should be used in the code as specified.
#### Formulae
```json
[
"effector/babel-plugin",
{
"importName": ["effector"]
}
]
```
* Type: `string | string[]`
* Default: `['effector', 'effector/compat']`
### `factories`
Accepts an array of module names which exports treat as custom factories, therefore, each function call provides a unique prefix for sids of units inside them. Used to
SSR(Server Side Rendering) and it's not required for client-only application.
> INFO since:
>
> [effector 21.6.0](https://changelog.effector.dev/#effector-21-6-0)
#### Formulae
```json
[
"effector/babel-plugin",
{
"factories": ["path/here"]
}
]
```
* Type: `string[]`
* Factories can have any number of arguments.
* Factories can create any number of units.
* Factories can call any effector methods.
* Factories can call other factories from other modules.
* Modules with factories can export any number of functions.
* Factories should be compiled with `effector/babel-plugin` as well as code which use them.
#### Examples
```json
// .babelrc
{
"plugins": [
[
"effector/babel-plugin",
{
"factories": ["src/createEffectStatus", "~/createCommonPending"]
}
]
]
}
```
```js
// ./src/createEffectStatus.js
import { rootDomain } from "./rootDomain";
export function createEffectStatus(fx) {
const $status = rootDomain.createStore("init").on(fx.finally, (_, { status }) => status);
return $status;
}
```
```js
// ./src/statuses.js
import { createEffectStatus } from "./createEffectStatus";
import { fetchUserFx, fetchFriendsFx } from "./api";
export const $fetchUserStatus = createEffectStatus(fetchUserFx);
export const $fetchFriendsStatus = createEffectStatus(fetchFriendsFx);
```
Import `createEffectStatus` from `'./createEffectStatus'` was treated as factory function, so each store created by it
has its own sid and will be handled by serialize
independently, although without `factories` they will share the same `sid`.
### `reactSsr`
Replaces imports from `effector-react` to `effector-react/scope`. Useful for building both server-side and client-side
builds from the same codebase.
> WARNING Deprecated:
>
> Since [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0) the core team recommends deleting this option from `babel-plugin` configuration because effector-react supports SSR by default.
#### Formulae
```json
[
"effector/babel-plugin",
{
"reactSsr": false
}
]
```
* Type: `boolean`
* Default: `false`
### `addNames`
Adds name to units factories call. Useful for minification and obfuscation of production builds.
> INFO since:
>
> [effector 21.8.0](https://changelog.effector.dev/#effector-21-8-0)
#### Formulae
```json
[
"effector/babel-plugin",
{
"addNames": true
}
]
```
* Type: `boolean`
* Default: `true`
### `addLoc`
Adds location to methods' calls. Used by devtools, for example [effector-logger](https://github.com/effector/logger).
#### Formulae
```json
[
"effector/babel-plugin",
{
"addLoc": false
}
]
```
* Type: `boolean`
* Default: `false`
### `debugSids`
Adds a file path and variable name of a unit definition to a sid. Useful for debugging SSR.
#### Formulae
```json
[
"effector/babel-plugin",
{
"debugSids": false
}
]
```
* Type: `boolean`
* Default: `false`
### `noDefaults`
Option for `effector/babel-plugin` for making custom unit factories with clean configuration.
> INFO since:
>
> [effector 20.2.0](https://changelog.effector.dev/#effector-20-2-0)
#### Formulae
```json
[
"effector/babel-plugin",
{
"noDefaults": false
}
]
```
* Type: `boolean`
* Default: `false`
#### Examples
```json
// .babelrc
{
"plugins": [
["effector/babel-plugin", { "addLoc": true }],
[
"effector/babel-plugin",
{
"importName": "@lib/createInputField",
"storeCreators": ["createInputField"],
"noDefaults": true
},
"createInputField"
]
]
}
```
```js
// @lib/createInputField.js
import { createStore } from "effector";
import { resetForm } from "./form";
export function createInputField(defaultState, { sid, name }) {
return createStore(defaultState, { sid, name }).reset(resetForm);
}
```
```js
// src/state.js
import { createInputField } from "@lib/createInputField";
const foo = createInputField("-");
/*
will be treated as store creator and compiled to
const foo = createInputField('-', {
name: 'foo',
sid: 'z&si65'
})
*/
```
## Usage with Bundlers
### Vite + React (SSR)
To use with `effector/babel-plugin`, you have to following next steps:
1. Install `@vitejs/plugin-react` package.
2. `vite.config.js` should be follows:
> Note: `effector/babel-plugin` is not a package, it is bundled with `effector`
```js
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
react({
babel: {
plugins: ["effector/babel-plugin"],
// Use .babelrc files
babelrc: true,
// Use babel.config.js files
configFile: true,
},
}),
],
});
```
# clearNode
```ts
import { clearNode } from "effector";
```
Method for destroying stores, events, effects, subscriptions, and domains.
## Methods
### `clearNode(unit, config?)`
#### Formulae
```ts
clearNode(unit, config?: {deep?: boolean}): void
```
#### Arguments
1. `unit` (////): unit to be erased.
2. `config: {}` (optional): config object.
* `deep?: boolean` (optional): erase node *and* all of its computed values.
#### Returns
`void`
#### Examples
##### Simple
```js
import { createStore, createEvent, clearNode } from "effector";
const inc = createEvent();
const $store = createStore(0).on(inc, (x) => x + 1);
inc.watch(() => console.log("inc called"));
$store.watch((x) => console.log("store state: ", x));
// => store state: 0
inc();
// => inc called
// => store state: 1
clearNode($store);
inc();
// => inc called
```
Try it
##### Deep clear
```js
import { createStore, createEvent, clearNode } from "effector";
const inc = createEvent();
const trigger = inc.prepend(() => {});
const $store = createStore(0).on(inc, (x) => x + 1);
trigger.watch(() => console.log("trigger called"));
inc.watch(() => console.log("inc called"));
$store.watch((x) => console.log("store state: ", x));
// => store state: 0
trigger();
// => trigger called
// => inc called
// => store state: 1
clearNode(trigger, { deep: true });
trigger();
// no reaction
inc();
// no reaction!
// all units, which depend on trigger, are erased
// including inc and store, because it depends on inc
```
Try it
# combine
import LiveDemo from "../../../../../components/LiveDemo.jsx";
This method allows retrieving the state from each passed store and combining them into a single value, storing it in a new derived store.
The resulting store will update every time any of the passed stores is updated.
If several stores update simultaneously, the method will process them all at once, meaning that `combine` batches updates, which leads to more efficient operation without unnecessary computations.
> WARNING Caution:
>
> `combine` returns not just a common store. Instead, it returns DerivedStore, it cannot be modified by the events or used as `target` in sample.
## Common formulae
```ts
declare const $a: Store;
declare const $b: Store;
// State transformation
const $c: Store = combine({ a: $a, b: $b }, (values: { a: A; b: B }) => C);
const $c: Store = combine([$a, $b], (values: [A, B]) => C);
const $c: Store = combine($a, $b, (a: A, b: B) => C);
// State combination
const $c: Store<{ a: A; b: B }> = combine({ a: $a, b: $b });
const $c: Store<[A, B]> = combine([$a, $b]);
```
## State transformation
When function is passed to `combine` it will act as state transformation funciton which will be called at every `combine` update.
Result will be saved in created store. This function must be .
`combine` function called synchronously during combine call, if this function will throw an error, application will crash. This will be fixed in [24 release](https://github.com/effector/effector/issues/1163)
### `combine(...stores, fn)`
#### Formulae
```ts
const $a: Store
const $b: StoreWritable
const $c: Store | StoreWritable
$result: Store = combine(
$a, $b, $c, ...,
(a: A, b: B, c: C, ...) => result
)
```
* After call `combine`, state of each store is extracted and passed to function arguments, `result` of a function call will be state of store `$result`
* Any number of stores can be passed to `combine`, but the latest argument always should be function-reducer that returns new state
* If function returned the same `result` as previous, store `$result` will not be triggered
* If several stores updated at the same time (during one tick) there will be single call of function and single update of `$result` store
* Function must be
#### Returns
: New derived store
#### Examples
import demo\_combineStoresFn from "../../../../demo/combine/stores-fn.live.js?raw";
### `combine({ A, B, C }, fn)`
#### Formulae
```ts
const $a: Store;
const $b: StoreWritable;
const $c: Store | StoreWritable;
$result: Store = combine(
{ a: $a, b: $b, c: $c },
({ a, b, c }: { a: A; b: B; c: C }): D => result,
);
```
* Read state from stores `$a`, `$b`, `$c` and assign it to properties `a`, `b`, `c` accordingly, calls function with that object
* The `result` of the function call saved in `$result` store
* If function returned the same `result` as previous, store `$result` will not be triggered
* If several stores updated at the same time (during one tick) there will be single call of function and single update of `$result` store
* Function must be
#### Returns
: New derived store
#### Examples
import demo\_combineObjectFn from "../../../../demo/combine/object-fn.live.js?raw";
### `combine([ A, B, C ], fn)`
#### Formulae
```ts
const $a: Store;
const $b: StoreWritable;
const $c: Store | StoreWritable;
$result: Store = combine([$a, $b, $c], ([A, B, C]): D => result);
```
* Read state from stores `$a`, `$b`, `$c` and assign it to array with the same order as passed stores, call function with that array
* The `result` of the function call saved in `$result` store
* If function returned the same `result` as previous, store `$result` will not be triggered
* If several stores updated at the same time (during one tick) there will be single call of function and single update of `$result` store
* Function must be
#### Returns
: New derived store
#### Examples
import demo\_combineArrayFn from "../../../../demo/combine/array-fn.live.js?raw";
## State combination
When there is no function in `combine` it will act as state combinator, creating a store with array or object with fields from given stores
### `combine({ A, B, C })`
> INFO:
>
> Formerly known as `createStoreObject`
#### Formulae
```ts
const $a: Store;
const $b: StoreWritable;
const $c: Store | StoreWritable;
$result: Store<{ a: A; b: B; c: C }> = combine({ a: $a, b: $b, c: $c });
```
* Read state from stores `$a`, `$b`, `$c` and assign it to properties `a`, `b`, `c` accordingly, that object will be saved to `$result` store
* Store `$result` contain object `{a, b, c}` and will be updated on each update of passed stores
* If several stores updated at the same time (during one tick) there will be single update of `$result` store
#### Returns
: New derived store
#### Examples
import demo\_combineObject from "../../../../demo/combine/object.live.js?raw";
### `combine([ A, B, C ])`
#### Formulae
```ts
const $a: Store;
const $b: StoreWritable;
const $c: Store | StoreWritable;
$result: Store<[A, B, C]> = combine([$a, $b, $c]);
```
* Read state from stores `$a`, `$b`, `$c` and assign it to array with the same order as passed stores, that array will be saved to `$result` store
* Store `$result` will be updated on each update of passed stores
* If several stores updated at the same time (during one tick) there will be single update of `$result` store
#### Returns
: New derived store
#### Examples
import demo\_combineArray from "../../../../demo/combine/array.live.js?raw";
## `combine` with primitives and objects
Primitives and objects can be used in `combine`, and `combine` will not be triggered. Effector will not track mutations of objects and primitives.
#### Examples
import demo\_combineNonStoresFn from "../../../../demo/combine/non-stores-fn.live.js?raw";
## Parameters
All overloads of `combine` with `fn` provided are also supporting optional configuration object as the last parameter.
### `.skipVoid`
Flag to control how specifically store should handle `undefined` value *(since `effector 23.0.0`)*. If set to `false` - store will use `undefined` as a value. If set to `true` (deprecated), store will read `undefined` as a "skip update" command and will do nothing
#### Formulae
```ts
combine($a, $b, callback, { skipVoid: true });
```
* Type: `boolean`
#### Examples
```js
const $withFn = combine($a, $b, (a, b) => a || b, { skipVoid: false });
```
# createApi
```ts
import { createApi } from "effector";
```
`createApi` is a shortcut for generating events connected to a store by supplying an object with for these events. If the source `store` is part of a domain, then the newly created events will also be within that domain.
## Methods
### `createApi(store, api)`
#### Formulae
```ts
createApi(store, api): objectWithEvents
```
#### Arguments
1. `store`
2. `api` (*Object*) An object with
#### Returns
(*Object*) An object with events
#### Examples
```js
import { createStore, createApi } from "effector";
const $playerPosition = createStore(0);
// Creating events and attaching them to the store
const api = createApi($playerPosition, {
moveLeft: (pos, offset) => pos - offset,
moveRight: (pos, offset) => pos + offset,
});
$playerPosition.watch((pos) => {
console.log("position", pos);
});
// => position 0
api.moveRight(10);
// => position 10
api.moveLeft(5);
// => position 5
```
Try it
# createDomain
```ts
import { createDomain, type Domain } from "effector";
```
## Methods
### `createDomain(name?)`
Creates a domain
#### Formulae
```typescript
createDomain(name?): Domain
```
#### Arguments
1. `name`? (*string*): domain name. Useful for debugging
#### Returns
: New domain
#### Examples
```js
import { createDomain } from "effector";
const domain = createDomain(); // Unnamed domain
const httpDomain = createDomain("http"); // Named domain
const statusCodeChanged = httpDomain.createEvent();
const downloadFx = httpDomain.createEffect();
const apiDomain = httpDomain.createDomain(); // nested domain
const $data = httpDomain.createStore({ status: -1 });
```
Try it
# createEffect
```ts
import { createEffect, type Effect } from "effector";
```
Method for creating an effect.
## Methods
### `createEffect(handler)`
Creates an effect with the given handler.
#### Formulae
```typescript
createEffect(handler?): Effect
```
#### Arguments
1. `handler` (*Function*): Function to handle effect calls, can also be set using .use(handler).
#### Returns
: A new effect.
> TIP Reminder:
>
> You must provide a handler either in createEffect or in .use method later; otherwise, the effect will throw with the `no handler used in _%effect name%_` error.
> INFO since:
>
> [effector 21.3.0](https://changelog.effector.dev/#effector-21-3-0)
#### Examples
##### Create effect with handler
```js
import { createEffect } from "effector";
const fetchUserReposFx = createEffect(async ({ name }) => {
const url = `https://api.github.com/users/${name}/repos`;
const req = await fetch(url);
return req.json();
});
fetchUserReposFx.done.watch(({ params, result }) => {
console.log(result);
});
await fetchUserReposFx({ name: "zerobias" });
```
Try it
##### Change state on effect completion
```js
import { createStore, createEffect } from "effector";
const fetchUserReposFx = createEffect(async ({ name }) => {
const url = `https://api.github.com/users/${name}/repos`;
const req = await fetch(url);
return req.json();
});
const $repos = createStore([]).on(fetchUserReposFx.doneData, (_, repos) => repos);
$repos.watch((repos) => {
console.log(`${repos.length} repos`);
});
// => 0 repos
await fetchUserReposFx({ name: "zerobias" });
// => 26 repos
```
Try it
##### Set handler to effect after creating
```js
import { createEffect } from "effector";
const fetchUserReposFx = createEffect();
fetchUserReposFx.use(async ({ name }) => {
const url = `https://api.github.com/users/${name}/repos`;
const req = await fetch(url);
return req.json();
});
await fetchUserReposFx({ name: "zerobias" });
```
Try it
##### Watch effect status
```js
import { createEffect } from "effector";
const fetchUserReposFx = createEffect(async ({ name }) => {
const url = `https://api.github.com/users/${name}/repos`;
const req = await fetch(url);
return req.json();
});
fetchUserReposFx.pending.watch((pending) => {
console.log(`effect is pending?: ${pending ? "yes" : "no"}`);
});
fetchUserReposFx.done.watch(({ params, result }) => {
console.log(params); // {name: 'zerobias'}
console.log(result); // resolved value
});
fetchUserReposFx.fail.watch(({ params, error }) => {
console.error(params); // {name: 'zerobias'}
console.error(error); // rejected value
});
fetchUserReposFx.finally.watch(({ params, status, result, error }) => {
console.log(params); // {name: 'zerobias'}
console.log(`handler status: ${status}`);
if (error) {
console.error("handler rejected", error);
} else {
console.log("handler resolved", result);
}
});
await fetchUserReposFx({ name: "zerobias" });
```
Try it
### `createEffect(config)`
Creates an effect with handler and name from a given config object.
#### Formulae
```typescript
createEffect({ handler, name }): Effect
```
#### Arguments
1. `config?: {}` (*Object*): Effect configuration.
* `handler` (*Function*): Function to handle effect calls, can also be set using .use(handler).
* `name?` (*string*): Optional effect name.
#### Returns
: A new effect.
#### Examples
##### Create named effect
```js
import { createEffect } from "effector";
const fetchUserReposFx = createEffect({
name: "fetch user repositories",
async handler({ name }) {
const url = `https://api.github.com/users/${name}/repos`;
const req = await fetch(url);
return req.json();
},
});
await fetchUserReposFx({ name: "zerobias" });
```
Try it
# createEvent
```ts
import { createEvent } from "effector";
```
## Methods
### `createEvent(name?)`
Method for creating an event.
#### Formulae
```ts
createEvent(name?): Event
createEvent(name?): Event
```
#### Arguments
1. `name`? (*string*): Event name
#### Returns
: New event
#### Notes
Event β it is a function which allows to change state when called (see simple example) also it can be a good way to extract data (see map and watch example). Also, it allows us to send data to another event or effect via effector operators.
#### Examples
##### Simple
```js
import { createStore, createEvent } from "effector";
const incrementBy = createEvent();
const resetCounter = createEvent();
const $counter = createStore(0);
$counter.on(incrementBy, (counter, number) => counter + number).reset(resetCounter);
$counter.watch((counter) => {
console.log("counter is now", counter);
});
// => counter is now 0
incrementBy(10);
// => counter is now 10
incrementBy(10);
// => counter is now 20
incrementBy(10);
// => counter is now 30
resetCounter();
// => counter is now 0
```
Try it
We created a store `$counter` and an event `incrementBy`, and started watching the store.
Notice the function call `incrementBy(10)`. Whenever you will call `incrementBy(10)`, you can look at the console and see how state of `$counter` changes.
##### Using `.map` and `.watch`
```js
import { createEvent } from "effector";
const fullNameReceived = createEvent();
const firstNameReceived = fullNameReceived.map((fullName) => fullName.split(" ")[0]);
const lastNameReceived = fullNameReceived.map((fullName) => fullName.split(" ")[1]);
const firstNameUppercaseReceived = firstNameReceived.map((firstName) => firstName.toUpperCase());
firstNameReceived.watch((firstName) => console.log("First name", firstName));
lastNameReceived.watch((lastName) => console.log("Last name", lastName));
firstNameUppercaseReceived.watch((firstName) => console.log("Upper case", firstName));
fullNameReceived("John Doe");
// => First name John
// => Last name Doe
// => Upper case JOHN
```
Try it
# createStore
```ts
import { createStore, type Store, type StoreWritable } from "effector";
```
## Methods
### `createStore(defaultState)`
Method for creating a store.
#### Formulae
```ts
createStore(defaultState: T): StoreWritable
```
#### Arguments
1. `defaultState` (*State*): Default state
#### Throws
##### unit call from pure function is not supported, use operators like sample instead
> Since: effector 23.0.0
Occurs when events or effects are called from pure functions, like updateFilter:
```ts
const someHappened = createEvent();
const $counter = createStore(0, {
updateFilter(a, b) {
someHappened(a); // THROWS!
return a < b;
},
});
```
To resolve this, use `sample`:
```ts
const someHappened = createEvent();
const $counter = createStore(0, {
updateFilter(a, b) {
return a < b;
},
});
sample({
clock: $counter,
target: someHappened,
});
```
#### Returns
: New store
#### Examples
##### Basic
```js
import { createEvent, createStore } from "effector";
const addTodo = createEvent();
const clearTodoList = createEvent();
const $todos = createStore([])
// Will update store when addTodo is fired
.on(addTodo, (list, todo) => [...list, todo])
// Will reset store to default state when clearTodos is fired
.reset(clearTodoList);
// Create mapped store
const $selectedTodos = $todos.map((todos) => {
return todos.filter((todo) => todo.selected);
});
// Log initial store value and each change
$todos.watch((todos) => {
console.log("todos", todos);
});
// => todos []
addTodo("go shopping");
// => todos ['go shopping']
addTodo("go to the gym");
// => todos ['go shopping', 'go to the gym']
clearTodoList();
// => todos []
```
Try it
### `createStore(defaultState, config)`
Method for creating a store but with configuration.
#### Formulae
```ts
createStore(defaultState: T, config: {
name?: string
updateFilter?: (update: T, current: T) => boolean
skipVoid?: boolean
serialize?: 'ignore' | {
write: (state: State) => SerializedState
read: (json: SerializedState) => State
}
}): StoreWritable
```
#### Arguments
1. `defaultState` (*State*): Default state
2. `config` (*Object*): Optional configuration
* `name` (*String*): Name for the store. Babel plugin can set it from the variable name, if not passed explicitly in config.
* `updateFilter` (*Function*): Function that prevents store from updating when it returns `false`. Accepts updated state as the first argument and current state as the second argument. Redundant for most cases since store already ensures that update is not `undefined` and not equal (`!==`) to current state *(since `effector 21.8.0`)*
* `serialize: 'ignore'`: Option to disable store serialization when serialize is called *(since `effector 22.0.0`)*
* `serialize` (*Object*): Configuration object to handle store state serialization in custom way. `write` β called on serialize, transforms value to JSON value β primitive type or plain object/array. `read` β parse store state from JSON value, called on fork, if provided `values` is the result of `serialize` call.
* `domain`: (*Domain*): Domain to attach store to after creation.
* `skipVoid`: (*boolean*): Flag to control how specifically store should handle `undefined` value *(since `effector 23.0.0`)*. If set to `false` - store will use `undefined` as a value. If set to `true` (deprecated), store will interpret `undefined` as a "skip update" command and will do nothing.
#### Throws
The same behaviour like for regular createStore(defaultState).
#### Returns
: New store
#### Examples
##### With `updateFilter`
```js
import { createEvent, createStore, sample } from "effector";
const punch = createEvent();
const veryStrongHit = createEvent();
const $lastPunchStrength = createStore(0, {
// If store should be updated with strength less than 400 kg
// update will be skipped
updateFilter: (strength) => strength >= 400,
});
$lastPunchStrength.on(punch, (_, strength) => strength);
// Each store update should trigger event `veryStrongHit`
sample({ clock: $lastPunchStrength, target: veryStrongHit });
// Watch on store prints initial state
$lastPunchStrength.watch((strength) => console.log("Strength: %skg", strength));
// => Strength: 0kg
veryStrongHit.watch((strength) => {
console.log("Wooow! It was very strong! %skg", strength);
});
punch(200); // updateFilter prevented update
punch(300); // Same here, store doesn't update, value remains `0`
punch(500); // Yeeah! updateFilter allows store update
// => Strength: 500kg
// => Wooow! It was very strong! 500kg
punch(100); // No update as well
```
Try it
##### With `serialize: ignore`
```js
import { createEvent, createStore, serialize, fork, allSettled } from "effector";
const readPackage = createEvent();
const $name = createStore("");
const $version = createStore(0, { serialize: "ignore" });
$name.on(readPackage, (_, { name }) => name);
$version.on(readPackage, (_, { version }) => version);
// Watchers always called for scoped changes
$name.watch((name) => console.log("name '%s'", name));
$version.watch((version) => console.log("version %s", version));
// => name ''
// => version 0
// Please, note, `fork()` call doesn't trigger watches
// In the opposit of `hydrate()` call
const scope = fork();
// By default serialize saves value only for the changed stores
// Review `onlyChanges` option https://effector.dev/api/effector/serialize
const values = serialize(scope);
console.log(values);
// => {}
// Let's change our stores
await allSettled(readPackage, {
scope,
params: { name: "effector", version: 22 },
});
// => name 'effector'
// => version 22
const actualValues = serialize(scope);
console.log(actualValues);
// => {n74m6b: "effector"}
// `$version` store has `serialize: ignore`, so it's not included
```
Try it
##### Custom `serialize` configuration
```ts
import { createEvent, createStore, serialize, fork, allSettled } from "effector";
const saveDate = createEvent();
const $date = createStore(null, {
// Date object is automatically serialized to ISO date string by JSON.stringify
// but it is not parsed to Date object by JSON.parse
// which will lead to a mismatch during server side rendering
//
// Custom `serialize` config solves this issue
serialize: {
write: (dateOrNull) => (dateOrNull ? dateOrNull.toISOString() : dateOrNull),
read: (isoStringOrNull) => (isoStringOrNull ? new Date(isoStringOrNull) : isoStringOrNull),
},
}).on(saveDate, (_, p) => p);
const serverScope = fork();
await allSettled(saveDate, { scope: serverScope, params: new Date() });
const serverValues = serialize(serverScope);
// `serialize.write` of `$date` store is called
console.log(serverValues);
// => { nq1e2rb: "2022-11-05T15:38:53.108Z" }
// Date object saved as ISO string
const clientScope = fork({ values: serverValues });
// `serialize.read` of `$date` store is called
const currentValue = clientScope.getState($date);
console.log(currentValue);
// => Date 11/5/2022, 10:40:13 PM
// ISO date string is parsed back to Date object
```
Try it
# createWatch
```ts
import { createWatch } from "effector";
```
## Methods
### `createWatch(config)`
Creates a subscription on unit (store, event, or effect).
#### Formulae
```ts
createWatch(config: {
unit: Unit
fn: (payload: T) => void
scope?: Scope
}): Subscription
```
#### Arguments
1. `config` (*Object*): Configuration
* `unit` (*Unit*): Target unit (store, event of effect) that will be watched
* `fn` (*Function*): Function that will be called when the unit is triggered. Accepts the unit's payload as the first argument.
* `scope` (): An optional scope object (forked instance) to restrict watcher calls on particular scope.
#### Returns
: Unsubscribe function
#### Examples
##### With scope
```js
import { createWatch, createEvent, fork, allSettled } from "effector";
const changeName = createEvent();
const scope = fork();
const unwatch = createWatch({ unit: changeName, scope, fn: console.log });
await allSettled(changeName, { scope, params: "John" }); // output: John
changeName("John"); // no output
```
##### Without scope
```js
import { createWatch, createEvent, fork, allSettled } from "effector";
const changeName = createEvent();
const scope = fork();
const unwatch = createWatch({ unit: changeName, fn: console.log });
await allSettled(changeName, { scope, params: "John" }); // output: John
changeName("John"); // output: John
```
# fork
```ts
import { fork, type Scope } from "effector";
```
## Methods
### `fork()`
> INFO since:
>
> introduced in [effector 22.0.0](https://changelog.effector.dev/#effector-22-0-0)
Creates an isolated instance of application.
Primary purposes of this method are SSR and testing.
#### Formulae
```ts
fork(): Scope
```
#### Returns
: New fresh scope
#### Examples
##### Create two instances with independent counter state
```js
import { createStore, createEvent, fork, allSettled } from "effector";
const inc = createEvent();
const dec = createEvent();
const $counter = createStore(0);
$counter.on(inc, (value) => value + 1);
$counter.on(dec, (value) => value - 1);
const scopeA = fork();
const scopeB = fork();
await allSettled(inc, { scope: scopeA });
await allSettled(dec, { scope: scopeB });
console.log($counter.getState()); // => 0
console.log(scopeA.getState($counter)); // => 1
console.log(scopeB.getState($counter)); // => -1
```
Try it
### `fork(options)`
Allows to set values for stores in scope and replace handlers for effects.
> INFO since:
>
> support for array of tuples in `values` and `handlers` introduced in [effector 22.0.0](https://changelog.effector.dev/#effector-22-0-0)
#### Formulae
```ts
fork(options: { values?, handlers? }): Scope
```
#### Arguments
1. `options: { values?, handlers? }` β Object with optional values and handlers
##### `values`
Option to provide initial states for stores.
Can be used in three ways:
1. Array of tuples with stores and values:
```ts
fork({
values: [
[$user, "alice"],
[$age, 21],
],
});
```
2. Map with stores and values:
```ts
fork({
values: new Map().set($user, "alice").set($age, 21),
});
```
3. Plain object: `{[sid: string]: value}`
```ts
fork({
values: {
[$user.sid]: "alice",
[$age.sid]: 21,
},
});
```
> INFO Explanation:
>
> Such objects are created by serialize, in application code **array of tuples is preferred**
##### `handlers`
Option to provide handlers for effects.
Can be used in different ways:
1. Array of tuples with effects and handlers:
```ts
fork({
handlers: [
[getMessageFx, (params) => ({ id: 0, text: "message" })],
[getUserFx, async (params) => ({ name: "alice", age: 21 })],
],
});
```
2. Map with effects and handlers:
```ts
fork({
handlers: new Map()
.set(getMessageFx, (params) => ({ id: 0, text: "message" }))
.set(getUserFx, async (params) => ({ name: "alice", age: 21 })),
});
```
3. Plain object: `{[sid: string]: handler}`
```ts
fork({
handlers: {
[getMessageFx.sid]: (params) => ({ id: 0, text: "message" }),
[getUserFx.sid]: async (params) => ({ name: "alice", age: 21 }),
},
});
```
> WARNING deprecation:
>
> Such objects are deprecated since [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0) and will be removed in future versions. Array of tuples is preferred.
#### Returns
: New fresh scope
#### Examples
##### Set initial state for store and change handler for effect
This is an example of test, which ensures that after a request to the server, the value of `$friends` is filled.
```ts
import { createEffect, createStore, fork, allSettled } from "effector";
const fetchFriendsFx = createEffect<{ limit: number }, string[]>(async ({ limit }) => {
/* some client-side data fetching */
return [];
});
const $user = createStore("guest");
const $friends = createStore([]);
$friends.on(fetchFriendsFx.doneData, (_, result) => result);
const testScope = fork({
values: [[$user, "alice"]],
handlers: [[fetchFriendsFx, () => ["bob", "carol"]]],
});
/* trigger computations in scope and await all called effects */
await allSettled(fetchFriendsFx, {
scope: testScope,
params: { limit: 10 },
});
/* check value of store in scope */
console.log(testScope.getState($friends));
// => ['bob', 'carol']
```
Try it
### `fork(domain, options?)`
> INFO since:
>
> Introduced in [effector 21.0.0](https://changelog.effector.dev/#effector-21-0-0)
> WARNING Deprecated:
>
> Since [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0).
>
> `fork` no longer requires `domain` as an argument, because it can automatically track all units starting from [effector 22.0.0](https://changelog.effector.dev/#effector-22-0-0).
#### Formulae
```ts
fork(domain: Domain, options?: { values?, handlers? }): Scope
```
#### Arguments
1. `domain` (): Optional domain to fork.
2. `options: { values?, handlers? }` β Object with optional values and handlers
#### Returns
: New fresh scope
#### Examples
TBD
# forward
```ts
import { forward, type Subscription } from "effector";
```
Method to create connection between units in a declarative way. Send updates from one set of units to another.
## Methods
### `forward({ from, to })`
> WARNING Deprecated:
>
> Since [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0).
>
> The core team recommends using sample instead of `forward`.
#### Formulae
```ts
forward({
from: Unit | Unit[],
to: Unit | Unit[]
}): Subscription
```
#### Arguments
1. `from` (Unit | Unit\[]): Source of updates. Forward will listen for changes of these units
* if an [*Event*][_Event_] is passed, `to` will be triggered on each event trigger and receives event argument
* if a [*Store*][_Store_] is passed, `to` will be triggered on each store **change** and receives new value of the store
* if an [*Effect*][_Effect_] is passed, `to` will be triggered on each effect call and receives effect parameter
* if an array of units is passed, `to` will be triggered when any unit in `from` array is triggered
2. `to` (Unit | Unit\[]): Target for updates. `forward` will trigger these units with data from `from`
* if passed an [*Event*][_Event_], it will be triggered with data from `from` unit
* if passed a [*Store*][_Store_], data from `from` unit will be written to store and **trigger its update**
* if passed an [*Effect*][_Effect_], it will be called with data from `from` unit as parameter
* if `to` is an array of units, each unit in that array will be triggered
#### Returns
Subscription: Unsubscribe function. It breaks connection between `from` and `to`. After call, `to` will not be triggered anymore.
> INFO since:
>
> Arrays of units are supported since [effector 20.6.0](https://changelog.effector.dev/#effector-20-6-0)
#### Examples
##### Send store updates to another store
```js
import { createStore, createEvent, forward } from "effector";
const $store = createStore(1);
const event = createEvent();
forward({
from: event,
to: $store,
});
$store.watch((state) => console.log("store changed: ", state));
// => store changed: 1
event(200);
// => store changed: 200
```
Try it
##### Forward between arrays of units
```js
import { createEvent, forward } from "effector";
const firstSource = createEvent();
const secondSource = createEvent();
const firstTarget = createEvent();
const secondTarget = createEvent();
forward({
from: [firstSource, secondSource],
to: [firstTarget, secondTarget],
});
firstTarget.watch((e) => console.log("first target", e));
secondTarget.watch((e) => console.log("second target", e));
firstSource("A");
// => first target A
// => second target A
secondSource("B");
// => first target B
// => second target B
```
Try it
[_effect_]: /en/api/effector/Effect
[_store_]: /en/api/effector/Store
[_event_]: /en/api/effector/Event
# fromObservable
```ts
import { fromObservable, type Observable } from "effector";
```
## Methods
### `fromObservable()`
Creates an event containing all items from an Observable.
#### Formulae
```ts
fromObservable(source: Observable): Event
```
#### Arguments
1. `observable` (*Observable*)
#### Returns
: New event
#### Examples
##### Basic use case
```js
import { interval } from "rxjs";
import { fromObservable } from "effector";
//emit value in sequence every 1 second
const source = interval(1000);
const event = fromObservable(source);
//output: 0,1,2,3,4,5....
event.watch(console.log);
```
# guard
```ts
import { guard } from "effector";
```
> WARNING Deprecated:
>
> Since [effector 23.0.0](https://changelog.effector.dev/#effector-23-0-0).
>
> The core team recommends using sample instead of `guard`.
Method for conditional event routing.
It provides a way to control one dataflow with the help of another: when the condition and the data are in different places, we can use `guard` with stores as filters to trigger events when condition state is true, thereby modulate signals without mixing them.
## Methods
### `guard({ clock?, source?, filter, target? })`
#### Formulae
```ts
guard({ clock?, source?, filter, target? }): target
```
> INFO:
>
> Either `clock` or `source` is required
When `clock` is triggered, check `filter` for [truthy] and call `target` with data from `source` if `true`.
* If `clock` is not passed, `guard` will be triggered on every `source` update
* If `source` is not passed, call `target` with data from `clock`
* If `target` is not passed, create with type of `source` and return it from `guard()`
* If `filter` is , check it value for [truthy]
* If `filter` is `Function`, call it with data from `source` and check result for [truthy]
[truthy]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy
> INFO since:
>
> `clock` in `guard` is available since [effector 21.8.0](https://changelog.effector.dev/#effector-21-8-0)
### `guard({source, filter, target?})`
#### Arguments
1. `params` (*Object*): Configuration object
#### Returns
, which fires upon `clock` trigger
#### Examples
##### Basic
```js
import { createStore, createEffect, createEvent, guard } from "effector";
const clickRequest = createEvent();
const fetchRequest = createEffect((n) => new Promise((rs) => setTimeout(rs, 2500, n)));
const $clicks = createStore(0).on(clickRequest, (x) => x + 1);
const $requestsCount = createStore(0).on(fetchRequest, (x) => x + 1);
const $isIdle = fetchRequest.pending.map((pending) => !pending);
/*
1. on clickRequest
2. if $isIdle is true
3. take current $clicks value
4. and call fetchRequest with it
*/
guard({
clock: clickRequest /* 1 */,
filter: $isIdle /* 2 */,
source: $clicks /* 3 */,
target: fetchRequest /* 4 */,
});
```
See ui visualization
##### Function predicate
```js
import { createEffect, createEvent, guard } from "effector";
const submitForm = createEvent();
const searchUser = createEffect();
guard({
source: submitForm,
filter: (user) => user.length > 0,
target: searchUser,
});
submitForm(""); // nothing happens
submitForm("alice"); // ~> searchUser('alice')
```
Try it
### `guard(source, {filter: booleanStore})`
#### Arguments
1. `source` (//): Source unit. Will trigger given `guard` on updates
2. `filter` (): Filter store
#### Examples
##### Store filter
```js
import { createEvent, createStore, createApi, guard } from "effector";
const trigger = createEvent();
const $unlocked = createStore(true);
const { lock, unlock } = createApi($unlocked, {
lock: () => false,
unlock: () => true,
});
const target = guard(trigger, {
filter: $unlocked,
});
target.watch(console.log);
trigger("A");
lock();
trigger("B"); // nothing happens
unlock();
trigger("C");
```
Try it
### `guard(source, {filter: predicate})`
#### Arguments
1. `source` (//): Source unit. Will trigger given `guard` on updates
2. `filter` (*(payload) => Boolean*): Predicate function, should be
#### Examples
##### Predicate function
```js
import { createEvent, guard } from "effector";
const source = createEvent();
const target = guard(source, {
filter: (x) => x > 0,
});
target.watch(() => {
console.log("target called");
});
source(0);
// nothing happens
source(1);
// target called
```
Try it
# hydrate
```ts
import { hydrate } from "effector";
```
A companion method for . Hydrates provided values into corresponding stores within a provided domain or scope. The main purpose is an application state hydration on the client side after SSR.
## Methods
### `hydrate(domainOrScope, {values})`
> WARNING:
>
> You need to make sure that the store is created beforehand, otherwise, the hydration might fail. This could be the case if you keep store initialization/hydration scripts separate from stores' creation.
#### Formulae
```ts
hydrate(domainOrScope: Domain | Scope, { values: Map, any> | {[sid: string]: any} }): void
```
#### Arguments
1. `domainOrScope`: domain or scope which will be filled with given `values`
2. `values`: a mapping from store sids to store values or a Map where keys are store objects and values contain initial store value
#### Returns
`void`
#### Examples
Populate store with a predefined value
```js
import { createStore, createDomain, fork, serialize, hydrate } from "effector";
const domain = createDomain();
const $store = domain.createStore(0);
hydrate(domain, {
values: {
[$store.sid]: 42,
},
});
console.log($store.getState()); // 42
```
Try it
# effector
Effector API reference:
### Unit Definitions
* Event\
* Effect\
* Store\
* Domain
* Scope
### Unit Creators
* createEvent()
* createStore(default)
* createEffect(handler)
* createDomain()
### Common Methods
* combine(...stores, f)
* attach({effect, mapParams, source})
* sample({clock, source, fn, target})
* merge(\[eventA, eventB])
* split(event, cases)
* createApi(store, api)
### Fork API
* fork()
* serialize(scope)
* allSettled(unit, { scope })
* scopeBind(event)
* hydrate(domain)
### Plugins
* effector/babel-plugin
* @effector-swc-plugin
### Utilities
* is
* fromObservable(observable)
### Low Level API
* clearNode()
* withRegion()
* launch()
* inspect()
### Import Map
Package `effector` provides couple different entry points for different purposes:
* effector/compat
* effector/inspect
* effector/babel-plugin
### Deprecated Methods
* forward({from, to})
* guard({source, filter, target})
# inspect
```ts
import { inspect } from "effector/inspect";
```
Special API methods designed to handle debugging and monitoring use cases without giving too much access to internals of your actual app.
Useful to create developer tools and production monitoring and observability instruments.
## Inspect API
Allows us to track any computations that have happened in the effector's kernel.
### `inspect()`
#### Example
```ts
import { inspect, type Message } from "effector/inspect";
import { someEvent } from "./app-code";
function logInspectMessage(m: Message) {
const { name, value, kind } = m;
return console.log(`[${kind}] ${name} ${value}`);
}
inspect({
fn: (m) => {
logInspectMessage(m);
},
});
someEvent(42);
// will log something like
// [event] someEvent 42
// [on] 42
// [store] $count 1337
// βοΈ let's say that reducer adds 1295 to provided number
//
// and so on, any triggers
```
Scope limits the extent to which computations can be tracked. If no scope is provided - default out-of-scope mode computations will be tracked.
```ts
import { fork, allSettled } from "effector";
import { inspect, type Message } from "effector/inspect";
import { someEvent } from "./app-code";
function logInspectMessage(m: Message) {
const { name, value, kind } = m;
return console.log(`[${kind}] ${name} ${value}`);
}
const myScope = fork();
inspect({
scope: myScope,
fn: (m) => {
logInspectMessage(m);
},
});
someEvent(42);
// βοΈ No logs! That's because tracking was restricted by myScope
allSettled(someEvent, { scope: myScope, params: 42 });
// [event] someEvent 42
// [on] 42
// [store] $count 1337
```
### Tracing
Adding `trace: true` setting allows looking up previous computations, that led to this specific one. It is useful to debug the specific reason for some events happening
#### Example
```ts
import { fork, allSettled } from "effector";
import { inspect, type Message } from "effector/inspect";
import { someEvent, $count } from "./app-code";
function logInspectMessage(m: Message) {
const { name, value, kind } = m;
return console.log(`[${kind}] ${name} ${value}`);
}
const myScope = fork();
inspect({
scope: myScope,
trace: true, // <- explicit setting is needed
fn: (m) => {
if (m.kind === "store" && m.sid === $count.sid) {
m.trace.forEach((tracedMessage) => {
logInspectMessage(tracedMessage);
// βοΈ here we are logging the trace of specific store update
});
}
},
});
allSettled(someEvent, { scope: myScope, params: 42 });
// [on] 42
// [event] someEvent 42
// βοΈ traces are provided in backwards order, because we are looking back in time
```
### Errors
Effector does not allow exceptions in pure functions. In such case, branch computation is stopped and an exception is logged. There is also a special message type in such case:
#### Example
```ts
inspect({
fn: (m) => {
if (m.type === "error") {
// do something about it
console.log(`${m.kind} ${m.name} computation has failed with ${m.error}`);
}
},
});
```
## Inspect Graph
Allows us to track declarations of units, factories, and regions.
### Example
```ts
import { createStore } from "effector";
import { inspectGraph, type Declaration } from "effector/inspect";
function printDeclaration(d: Declaration) {
console.log(`${d.kind} ${d.name}`);
}
inspectGraph({
fn: (d) => {
printDeclaration(d);
},
});
const $count = createStore(0);
// logs "store $count" to console
```
### `withRegion`
Meta-data provided via region's root node is available on declaration.
#### Example
```ts
import { createNode, withRegion, createStore } from "effector";
import { inspectGraph, type Declaration } from "effector/inspect";
function createCustomSomething(config) {
const $something = createStore(0);
withRegion(createNode({ meta: { hello: "world" } }), () => {
// some code
});
return $something;
}
inspectGraph({
fn: (d) => {
if (d.type === "region") console.log(d.meta.hello);
},
});
const $some = createCustomSomething({});
// logs "world"
```
# is
```ts
import { is, type Unit } from "effector";
```
Namespace for unit validators.
## Methods
### `is.store(value)`
Checks if given value is
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { is, createStore, createEvent, createEffect, createDomain } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
is.store($store);
// => true
is.store(event);
// => false
is.store(fx);
// => false
is.store(createDomain());
// => false
is.store(fx.pending);
// => true
is.store(fx.done);
// => false
is.store($store.updates);
// => false
is.store(null);
// => false
```
Try it
### `is.event(value)`
Checks if given value is
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { is, createStore, createEvent, createEffect, createDomain } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
is.event($store);
// => false
is.event(event);
// => true
is.event(fx);
// => false
is.event(createDomain());
// => false
is.event(fx.pending);
// => false
is.event(fx.done);
// => true
is.event($store.updates);
// => true
is.event(null);
// => false
```
Try it
### `is.effect(value)`
Checks if given value is
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { is, createStore, createEvent, createEffect, createDomain } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
is.effect($store);
// => false
is.effect(event);
// => false
is.effect(fx);
// => true
is.effect(createDomain());
// => false
is.effect(null);
// => false
```
Try it
### `is.targetable`
Checks if given value can be used in operators target (or be called as a function in case of events)
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { is, createStore, createEvent, createEffect } from "effector";
const $store = createStore(null);
const $mapped = $store.map((x) => x);
const event = createEvent();
const mappedEvent = event.map((x) => x);
const fx = createEffect();
is.targetable($store);
// => true
is.targetable($mapped);
// => false
is.targetable(event);
// => true
is.targetable(mappedEvent);
// => false
is.targetable(fx);
// => true
```
### `is.domain(value)`
Checks if given value is
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { is, createStore, createEvent, createEffect, createDomain } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
is.domain($store);
// => false
is.domain(event);
// => false
is.domain(fx);
// => false
is.domain(createDomain());
// => true
is.domain(null);
// => false
```
Try it
### `is.scope(value)`
> INFO since:
>
> [effector 22.0.0](https://changelog.effector.dev/#effector-22-0-0)
Checks if given value is since [effector 22.0.0](https://changelog.effector.dev/#effector-22-0-0).
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { fork } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
const scope = fork();
is.scope(scope);
// => true
is.scope($store);
// => false
is.scope(event);
// => false
is.scope(fx);
// => false
is.scope(createDomain());
// => false
is.scope(null);
// => false
```
Try it
### `is.unit(value)`
Checks if given value is Unit: Store, Event, Effect, Domain or Scope
#### Returns
`boolean` β Type-guard
#### Examples
```js
import { is, createStore, createEvent, createEffect, createDomain, fork } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
const scope = fork();
is.unit(scope);
// => true
is.unit($store);
// => true
is.unit(event);
// => true
is.unit(fx);
// => true
is.unit(createDomain());
// => true
is.unit(fx.pending);
// => true
is.unit(fx.done);
// => true
is.unit($store.updates);
// => true
is.unit(null);
// => false
```
Try it
### `is.attached(value)`
> INFO since:
>
> [effector 22.4.0](https://changelog.effector.dev/#effector-22-4-0)
Checks if given value is created via method. If passed not an effect, returns `false`.
#### Returns
`boolean` β Type-guard
#### Usage
Sometimes you need to add an error log on effects failures, but only on effects that have been "localized" via `attach`.
If you leave `onCreateEffect` as it is, without checks, the error log will be duplicated, because it will happen on the parent and the child effect.
```js
import { createDomain, attach, is } from "effector";
const logFailuresDomain = createDomain();
logFailuresDomain.onCreateEffect((effect) => {
if (is.attached(effect)) {
effect.fail.watch(({ params, error }) => {
console.warn(`Effect "${effect.compositeName.fullName}" failed`, params, error);
});
}
});
const baseRequestFx = logFailuresDomain.createEffect((path) => {
throw new Error(`path ${path}`);
});
const loadDataFx = attach({
mapParams: () => "/data",
effect: baseRequestFx,
});
const loadListFx = attach({
mapParams: () => "/list",
effect: baseRequestFx,
});
loadDataFx();
loadListFx();
```
Try it
#### Examples
```js
import { is, createStore, createEvent, createEffect, createDomain, attach } from "effector";
const $store = createStore(null);
const event = createEvent();
const fx = createEffect();
const childFx = attach({
effect: fx,
});
is.attached(childFx);
// => true
is.attached(fx);
// => false
is.attached($store);
// => false
is.attached(event);
// => false
is.attached(createDomain());
// => false
is.attached(null);
// => false
```
Try it
# launch
```ts
import { launch, type Unit, type Node } from "effector";
```
> INFO since:
>
> [effector 20.10.0](https://changelog.effector.dev/#effector-20-10-0)
## Methods
### `launch({ target, params })`
Low level method for running computation in units (events, effects or stores). Mostly used by library developers for fine-grained control of computations.
#### Formulae
```ts
launch({
target,
params,
defer?: boolean,
page?: any,
scope?: Scope,
meta?: Record,
}): void
```
#### Arguments
TBD
#### Returns
`void`
### `launch(unit, params)`
#### Formulae
```ts
launch(unit: Unit | Node, params: T): void
```
#### Returns
`void`
# merge
```ts
import { merge, type Unit } from "effector";
```
## Methods
### `merge(units)`
> INFO since:
>
> [effector 20.0.0](https://changelog.effector.dev/#effector-20-0-0)
Merges an array of units (events, effects, or stores), returning a new event that triggers upon any of the given units being triggered.
```ts
merge(units: Unit[]): Event
```
#### Arguments
1. `units`: An array of units to be merged.
#### Returns
: A new event that fires when any of the given units is triggered.
> TIP:
>
> In the case of a store, the resulting event will fire upon store updates.
#### Types
TBD
#### Examples
##### Basic Usage
```js
import { createEvent, merge } from "effector";
const foo = createEvent();
const bar = createEvent();
const baz = merge([foo, bar]);
baz.watch((v) => console.log("merged event triggered: ", v));
foo(1);
// => merged event triggered: 1
bar(2);
// => merged event triggered: 2
```
Try it
##### Working with Stores
```js
import { createEvent, createStore, merge } from "effector";
const setFoo = createEvent();
const setBar = createEvent();
const $foo = createStore(0).on(setFoo, (_, v) => v);
const $bar = createStore(100).on(setBar, (_, v) => v);
const anyUpdated = merge([$foo, $bar]);
anyUpdated.watch((v) => console.log(`state changed to: ${v}`));
setFoo(1); // => state changed to: 1
setBar(123); // => state changed to: 123
```
Try it
##### Merging a Store and an Event
```js
import { createEvent, createStore, merge } from "effector";
const setFoo = createEvent();
const otherEvent = createEvent();
const $foo = createStore(0).on(setFoo, (_, v) => v);
const merged = merge([$foo, otherEvent]);
merged.watch((v) => console.log(`merged event payload: ${v}`));
setFoo(999);
// => merged event payload: 999
otherEvent("bar");
// => merged event payload: bar
```
Try it
# effector/babel-plugin
Since Effector allows to automate many common tasks (like setting Stable IDentifiers and providing debug information for Units), there is a built-in plugin for Babel that enhances the developer experience when using the library.
## Usage
Please refer to the Babel plugin documentation for usage examples.
# effector/inspect
Effector has special API methods designed to handle debugging and monitoring use cases without giving too much access to the internals of your actual app β Inspect API.
### Why a Separate Module?
Inspect API is designed to be disposable. By design, any feature that uses Inspect API can be removed from the production build without any side effects. To emphasize this, Inspect API is not included in the main module. Instead, it's available in a separate module `effector/inspect`.
### Usage
Please refer to Inspect API docs for usage examples.
# effector/compat
```ts
import {} from "effector/compat";
```
The library provides a separate module with compatibility up to IE11 and Chrome 47 (browser for Smart TV devices).
> WARNING Bundler, Not Transpiler:
>
> Since third-party libraries can import `effector` directly, you **should not** use transpilers like Babel to replace `effector` with `effector/compat` in your code because by default, Babel will not transform third-party code.
>
> **Use a bundler instead**, as it will replace `effector` with `effector/compat` in all modules, including those from third parties.
### Required Polyfills
You need to install polyfills for these objects:
* `Promise`
* `Object.assign`
* `Array.prototype.flat`
* `Map`
* `Set`
In most cases, a bundler can automatically add polyfills.
#### Vite
Vite Configuration Example
```js
import { defineConfig } from "vite";
import legacy from "@vitejs/plugin-legacy";
export default defineConfig({
plugins: [
legacy({
polyfills: ["es.promise", "es.object.assign", "es.array.flat", "es.map", "es.set"],
}),
],
});
```
## Usage
### Manual Replacement
You can use `effector/compat` instead of the `effector` package if you need to support old browsers.
```diff
- import {createStore} from 'effector'
+ import {createStore} from 'effector/compat'
```
### Automatic Replacement
However, you can set up your bundler to automatically replace `effector` with `effector/compat` in your code.
#### Webpack
Webpack Configuration Example
```js
module.exports = {
resolve: {
alias: {
effector: "effector/compat",
},
},
};
```
#### Vite
Vite Configuration Example
```js
import { defineConfig } from "vite";
export default defineConfig({
resolve: {
alias: {
effector: "effector/compat",
},
},
});
```
# restore
```ts
import { restore } from "effector";
```
## Methods
### `restore(event, defaultState)`
Creates a from an . It works like a shortcut for `createStore(defaultState).on(event, (_, payload) => payload)`
> WARNING It is not a derived store:
>
> Restore creates a new store. It is not a DerivedStore. That means you can modify its state via events, and use it as `target` in sample.
#### Formulae
```ts
restore(event: Event, defaultState: T): StoreWritable
```
#### Arguments
1. `event`
2. `defaultState` (*Payload*)
#### Returns
: New store
#### Examples
##### Basic
```js
import { createEvent, restore } from "effector";
const event = createEvent();
const $store = restore(event, "default");
$store.watch((state) => console.log("state: ", state));
// state: default
event("foo");
// state: foo
```
Try it
### `restore(effect, defaultState)`
Creates a out of successful results of an . It works like a shortcut for `createStore(defaultState).on(effect.done, (_, {result}) => result)`
#### Formulae
```ts
restore(effect: Effect