Tarjima qoshish uchun havola boyicha o'tib Pull Request oching (havolaga o'tish).
Standart til uchun tarkibni ko'rsatadi.
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<T>
Construction
There are many ways to create an event:
- The most common
createEvent - Using Domain
createEvent - 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:
import { createEvent } from "effector";
interface ItemAdded {
id: string;
title: string;
}
const itemAdded = createEvent<ItemAdded>();
In most cases, there is no reason to use void with another type (). Use Event<void | number>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.
sample({
clock: withData, // Event<number>
target: withoutData, // Event<void>
});
We strongly recommend using null for empty values when intended:
import { createEvent } from "effector";
const maybeDataReceived = createEvent<Data | null>();
// maybeDataReceived: EventCallable<Data | null>
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
const event: EventCallable<T>;
event(argument: T): T;
eventcalled as a function always returns itsargumentas is- all subscribers of event receives the
argumentpassed into - when
Tisvoid,eventcan be called without arguments Tby default isvoid, so generic type argument can be omitted
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
argumentis a value ofT. It’s optional if the event is defined asEventCallable<void>.
Throws
call of readonly event is not supported, use createEvent instead
When user tried to call Event. In the most cases it happens when you tried to call derived event:
const numberReceived = createEvent<number>(); // EventCallable<number>
const stringifiedReceived = numberReceived.map((number) => String(number)); // Event<string>
stringifiedReceived("123"); // THROWS!
The same for all methods returning Event.
To fix it create separate event via createEvent, and connect them by sample:
const numberReceived = createEvent<number>();
const stringifiedReceived = createEvent<string>();
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
Happens when events or effects called from pure functions, like mappers:
const someHappened = createEvent<number>();
const another = createEvent();
const derived = someHappened.map((number) => {
another(); // THROWS!
return String(number);
});
To fix this, use sample:
const someHappened = createEvent<number>();
const another = createEvent();
const derived = createEvent<string>();
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
import { createEvent, Event } from "effector";
const someHappened = createEvent<number>();
// someHappened: EventCallable<number>
someHappened(1);
const anotherHappened = createEvent();
// anotherHappened: EventCallable<void>
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.
You can think of the EventCallable and Event as type and its super type:
EventCallable<T> extends Event<T>
.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
const first: EventCallable<T>;
const second: EventCallable<T> = first.prepend(fn);
- When
secondevent is triggered - Call
fnwith argument from thesecondevent - Trigger
firstevent with the result offn()
Arguments
fn(Function): A function that receivesargument, and should be pure.
Throws
unit call from pure function is not supported, use operators like sample instead
Happens when events or effects called from pure functions, like mappers:
const someHappened = createEvent<string>();
const another = createEvent<number>();
const reversed = someHappened.prepend((input: number) => {
another(input); // THROWS!
return String(input);
});
To fix this, use sample:
const someHappened = createEvent<string>();
const another = createEvent<number>();
const reversed = createEvent<number>();
// The same as .prepend(), but using `sample`
sample({
clock: reversed,
fn: (input) => String(input),
target: someHappened,
});
sample({
clock: reversed,
target: another,
});
Returns
EventCallable<T>: New event.
Types
There TypeScript requires explicitly setting type of the argument of fn function:
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
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
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:
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:
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<T>
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.
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<T> 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:
const event: Event<T>;
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
const first: Event<T> | EventCallable<T>;
const second: Event<F> = first.map(fn);
- When
firstis triggered, pass payload fromfirsttofn. - Trigger
secondwith the result of thefn()call as payload. - The function
fnis invoked each time thefirstevent is triggered. - Also, the
secondevent triggered each time thefirstis triggered.
Arguments
fn(Function): A function that receivesargument, and should be pure.
Throws
unit call from pure function is not supported, use operators like sample instead
Happens when events or effects called from pure functions, like mappers:
const someHappened = createEvent<number>();
const another = createEvent();
const derived = someHappened.map((number) => {
another(); // THROWS!
return String(number);
});
To fix this, use sample:
const someHappened = createEvent<number>();
const another = createEvent();
const derived = createEvent<string>();
sample({
clock: someHappened,
target: another,
});
// The same as .map(), but using `target`
sample({
clock: someHappened,
fn: (number) => String(number),
target: derived,
});
Returns
Event<T>: The new event.
Types
The resulting type of the fn function will be utilized to define the type of the derived event.
import { createEvent } from "effector";
const first = createEvent<number>();
// first: Event<number>
const second = first.map((count) => count.toString());
// second: Event<string>
The first event can be represented as either Event<T> or Event<T>.
The second event will always be represented as Event<T>.
Examples
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
.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.
sample operator with filter argument is the preferred filtering method.
Formulae
const first: Event<T> | EventCallable<T>;
const second: Event<T> = first.filter({ fn });
- When
firstis triggered, pass payload fromfirsttofn. - The
secondevent will be triggered only iffnreturnstrue, with the argument fromfirstevent. - The function
fnis invoked each time thefirstevent is triggered. - Also, the
secondevent triggered each time thefirstis triggered, and thefnreturnedtrue.
Arguments
fn(Function): A function that receivesargument, and should be pure.
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
Happens when events or effects called from pure functions, like guards:
const countReceived = createEvent<number>();
const eachReceived = createEvent<number>();
const receivedEven = someHappened.filter({
fn(count) {
eachReceived(count); // THROWS!
return count % 2 === 0;
},
});
To fix this, use sample to call eachReceived:
const countReceived = createEvent<number>();
const eachReceived = createEvent<number>();
const receivedEven = someHappened.filter({
fn(count) {
return count % 2 === 0;
},
});
sample({
clock: someHappened,
target: eachReceived,
});
Returns
Event<T>: The new event
Types
Method .filter() always returns Event. Also this event will have the same type as the original type:
import { createEvent } from "effector";
const numberReceived = createEvent<number>();
// numberReceived: Event<number>
const evenReceived = numberReceived.filter({
fn: (number) => number % 2 === 0,
});
// evenReceived: Event<number>
evenReceived.watch(console.info);
numberReceived(5); // nothing
numberReceived(2); // => 2
Examples
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
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.
const sneackersReceived = createEvent<Sneakers>();
const uniqueSizeReceived = sneackersReceived.filter({
fn: (sneackers) => sneackers.size === 48,
});
.filterMap(fn)
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
const first: Event<T> | EventCallable<T>;
const second: Event<F> = first.filterMap(fn);
- When
firstis triggered, callfnwith payload fromfirst - If
fn()returnedundefineddo not triggersecond - If
fn()returned some data, triggersecondwith data fromfn()
Arguments
fn(Function): A function that receivesargument, should be pure.
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
Happens when events or effects called from pure functions, like mappers:
const countReceived = createEvent<number>();
const eachReceived = createEvent<number>();
const receivedEven = someHappened.filterMap((count) => {
eachReceived(count); // THROWS!
return count % 2 === 0 ? Math.abs(count) : undefined;
});
To fix this, use sample to call eachReceived:
const countReceived = createEvent<number>();
const eachReceived = createEvent<number>();
const receivedEven = someHappened.filterMap((count) => {
return count % 2 === 0 ? Math.abs(count) : undefined;
});
sample({
clock: someHappened,
target: eachReceived,
});
Returns
Event<T>: 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:
import { createEvent } from "effector";
const first = createEvent<number>();
// first: Event<number>
const second = first.filterMap((count) => {
if (count === 0) return;
return count.toString();
});
// second: Event<string>
The first event can be represented as either Event<T> or EventCallable<T>.
The second event will always be represented as Event<T>.
Examples
import { createEvent } from "effector";
const listReceived = createEvent<string[]>();
// 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"]);
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:
- Take one apple;
- 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:
- Take an apple – event;
- Have a look, red or no – filter;
- You keep it – map;
- Put in pack – event.
- Pack – store
.watch(watcher)
This method enables you to call callback on each event trigger with the argument of the event.
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
const event: Event<T> | EventCallable<T>;
const unwatch: () => void = event.watch(fn);
- The
fnwill be called on eacheventtrigger, passed argument of theeventto thefn. - When
unwatchis called, stop callingfnon eacheventtrigger.
Arguments
watcher(Watcher): A function that receivesargumentfrom the event.
Returns
Subscription: Unsubscribe function.
Examples
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
.subscribe(observer)
This is the low-level method to integrate event with the standard Observable pattern.
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:
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.
It has the string | null type.
.shortName
It is a string type property, contains the name of the variable event declared at.
import { createEvent } from "effector";
const demo = createEvent();
// demo.shortName === 'demo'
But reassign event to another variable changes nothing:
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.
import { createEvent, createDomain } from "effector";
const first = createEvent();
const domain = createDomain();
const second = domain.createEvent();
console.log(first);
// => { shortName: "first", fullName: "first", path: ["first"] }
console.log(second);
// => { shortName: "second", fullName: "domain/second", path: ["domain", "second"] }
Types
import { type EventPayload } from "effector";
EventPayload<E>
Extracts type of payload from Event or EventCallable.
const event: Event<Payload>;
type Payload = EventPayload<typeof event>;
Ingliz tilidagi hujjatlar eng dolzarb hisoblanadi, chunki u effector guruhi tomonidan yozilgan va yangilanadi. Hujjatlarni boshqa tillarga tarjima qilish jamiyat tomonidan kuch va istaklar mavjud bo'lganda amalga oshiriladi.
Esda tutingki, tarjima qilingan maqolalar yangilanmasligi mumkin, shuning uchun eng aniq va dolzarb ma'lumot uchun hujjatlarning asl inglizcha versiyasidan foydalanishni tavsiya etamiz.