Event API

import { type Event, type EventCallable, createEvent } from "effector";

const event = createEvent();

An event in Effector represents a user action, a step in the application process, a command to execute, an intention to change something, and much more. An event acts as an entry point into the reactive data flow — a simple way to tell the app “something happened.”

this is your canonical event

If you’re not familiar with events and how to work with them, start here: What are events and how to use them.

Event Types

It’s important to understand that there are two types of events:

  1. Events, created using createEvent or .prepend. These events are of type EventCallable and can be triggered directly or used in the target argument of the sample method.
  2. Derived events, created using .map, .filter, or .filterMap. These are of type Event and cannot be triggered or passed into target — Effector triggers them internally in the correct order. However, you can subscribe to them via sample or watch.

Event Interface

Available methods and properties:

Method/Property
Description
prepend(fn)Creates a new event, transforms the input using fn, and passes it to the original event.
map(fn)Creates a new derived event triggered with the result of fn after the original event is fired.
filter({fn})Creates a new derived event that fires only if fn returns true.
filterMap(fn)Creates a new derived event triggered with fn if it’s not undefined.
watch(watcher)Adds a listener called on every event trigger.
subscribe(observer)Low-level method to integrate the event with the Observable pattern.
sidUnique unit identifier.
shortNameThe variable name in which the event is declared.
compositeNameFull composite name (domain + shortName) — useful for logging and tracing.

Event Methods

.prepend(fn)

info

This method exists only for events that are not derived (EventCallable)! That means it can only be used on events created with createEvent.

Creates a new EventCallable, which calls fn and passes the transformed data to the original event.

  • Formula
const second = first.prepend(fn);
  • Type
event.prepend<Before = void>(
  fn: (_: Before) => Payload
): EventCallable<Before>
  • Examples
import { createEvent } from "effector";

// original event
const userPropertyChanged = createEvent();

const changeName = userPropertyChanged.prepend((name) => ({
  field: "name",
  value: name,
}));
const changeRole = userPropertyChanged.prepend((role) => ({
  field: "role",
  value: role.toUpperCase(),
}));

userPropertyChanged.watch(({ field, value }) => {
  console.log(`User property "${field}" changed to ${value}`);
});

changeName("john");
// => User property "name" changed to john

changeRole("admin");
// => User property "role" changed to ADMIN

changeName("alice");
// => User property "name" changed to alice

Open example

You can treat this method as a wrapper function. Suppose you need to frequently call a function with an inconvenient API:

import { sendAnalytics } from "./analytics";

export function reportClick(item: string) {
  const argument = { type: "click", container: { items: [arg] } };
  return sendAnalytics(argument);
}

That’s exactly what .prepend() does:

import { sendAnalytics } from "./analytics";

export const reportClick = sendAnalytics.prepend((item: string) => {
  return { type: "click", container: { items: [arg] } };
});

reportClick("example");
// reportClick triggered "example"
// sendAnalytics triggered with { type: "click", container: { items: ["example"] } }
  • Detailed description

Works like a reversed .map. In .prepend, data is transformed before the event is triggered. In .map, it’s transformed after.

If the original event belongs to a domain, the new event will inherit that domain.

  • Return value

Returns a new event.


.map(fn)

Cleanliness is our everything!

The function fn must be pure.

Creates a new derived event, which is triggered after the original event, using the result of function fn as its argument.

  • Formula
// Works for any event — both regular and derived
const first: Event<T> | EventCallable<T>;
const second: Event<F> = first.map(fn);
  • Type
event.map<T>(fn: (payload: Payload) => T): Event<T>
  • Examples
import { createEvent } from "effector";

const userUpdated = createEvent<{ name: string; role: string }>();

// You can split data flow with .map()
const userNameUpdated = userUpdated.map(({ name }) => name);

// Or transform the data
const userRoleUpdated = userUpdated.map((user) => user.role.toUpperCase());

userNameUpdated.watch((name) => console.log(`User name is now [${name}]`));
userRoleUpdated.watch((role) => console.log(`User role is now [${role}]`));

userUpdated({ name: "john", role: "admin" });
// => User name is now [john]
// => User role is now [ADMIN]

Open example

  • Detailed description

The .map method allows you to split and control the data flow, extract fields, or transform values within your business logic.

  • Return value

Returns a new derived event.


.filter({ fn })

Tip

sample with the filter argument is the preferred method for filtering:

const event = createEvent();

const filteredEvent = sample({
  clock: event,
  filter: () => true,
});

.filter creates a derived event, which is triggered only if the function fn returns true. This is helpful for branching the data flow and reacting to specific conditions.

  • Formula
const first: Event<T> | EventCallable<T>;
const second: Event<T> = first.filter({ fn });
  • Type
event.filter(config: {
  fn(payload: Payload): boolean
}): Event<Payload>
  • Examples
import { createEvent, createStore } from "effector";

const numbers = createEvent();
const positiveNumbers = numbers.filter({
  fn: ({ x }) => x > 0,
});

const $lastPositive = createStore(0);

$lastPositive.on(positiveNumbers, (n, { x }) => x);

$lastPositive.watch((x) => {
  console.log("Last positive number:", x);
});

// => Last positive number: 0

numbers({ x: 0 }); // no output
numbers({ x: -10 }); // no output
numbers({ x: 10 }); // => Last positive number: 10

Open example

  • Return value

Returns a new derived event.


.filterMap(fn)

Our beloved sample

This method can also be replaced with a sample operation using the filter + fn arguments:

const event = createEvent();

const filteredAndMappedEvent = sample({
  clock: event,
  filter: () => true,
  fn: () => "value",
});

This method creates a derived event, which may be triggered if the result of fn is not undefined. It combines filtering and mapping in a single step.

Ideal for working with JavaScript APIs that sometimes return undefined.

  • Formula
const first: Event<T> | EventCallable<T>;
const second: Event<F> = first.filterMap(fn);
  • Type
event.filterMap<T>(fn: (payload: Payload) => T | undefined): Event<T>
  • Examples
import { createEvent } from "effector";

const listReceived = createEvent<string[]>();

// Array.prototype.find() returns undefined when the element isn't found
const effectorFound = listReceived.filterMap((list) => {
  return list.find((name) => name === "effector");
});

effectorFound.watch((name) => console.info("Found:", name));

listReceived(["redux", "effector", "mobx"]); // => Found: effector
listReceived(["redux", "mobx"]); // no output
Attention

The function fn must return some data. If undefined is returned, the derived event call will be skipped.

Open example

  • Return value

Returns a new derived event.


.watch(watcher)

The .watch method calls the provided watcher callback every time the event is triggered.

Remember

The watch method does not handle or report exceptions, does not manage the completion of asynchronous operations, and does not resolve data race conditions.

Its primary purpose is for short-term debugging and logging.

Learn more in the Events section.

  • Formula
const event: Event<T> | EventCallable<T>;
const unwatch: () => void = event.watch(fn);
  • Type
event.watch(watcher: (payload: Payload) => any): Subscription
  • Examples
import { createEvent } from "effector";

const sayHi = createEvent();
const unwatch = sayHi.watch((name) => console.log(`${name}, hello!`));

sayHi("Peter"); // => Peter, hello!
unwatch();

sayHi("Drew"); // => nothing happens

Open example

  • Return value

Returns a function to cancel the subscription.


.subscribe(observer)

This is a low-level method for integrating events with the standard Observable pattern.

Further reading:

Remember

You don’t need to use this method yourself. It’s used under the hood by rendering engines and so on.

  • Formula
const event = createEvent();

event.subscribe(observer);
  • Type
event.subscribe(observer: Observer<Payload>): Subscription
  • Examples
import { createEvent } from "effector";

const userLoggedIn = createEvent<string>();

const subscription = userLoggedIn.subscribe({
  next: (login) => {
    console.log("User login:", login);
  },
});

userLoggedIn("alice"); // => User login: alice

subscription.unsubscribe();
userLoggedIn("bob"); // => nothing happens

Event Properties

These properties are mainly set using effector/babel-plugin or @effector/swc-plugin, so they are only available when using Babel or SWC.

.sid

A unique identifier for each event.

SID is statically recorded in your application bundle and doesn’t change between app runs. This makes it perfect for identifying units across threads or between client and server.

Example: examples/worker-rpc

  • Type
interface Event {
  sid: string | null;
}

.shortName

Contains the variable name in which the event was declared.

import { createEvent } from "effector";

const demo = createEvent();
// demo.shortName === 'demo'

Reassigning the event to another variable doesn’t change this:

const another = demo;
// another.shortName === 'demo'
  • Type
interface Event {
  shortName: string;
}

.compositeName

Contains the full path of the event in your app’s structure. If the event was created inside a domain, its name will reflect that.

TIP

Usually, if a long name is required, it’s better to pass it explicitly in the name field.

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"]
// }
  • Type
interface Event {
  compositeName: {
    shortName: string;
    fullName: string;
    path: Array<string>;
  };
}

Event Peculiarities

  1. In Effector, every event supports only one argument. If you call an event like someEvent(first, second), only the first argument will be used — the rest are ignored.
  2. Inside event methods, you must not call other events or effects. All provided functions must be pure — no side effects, no async calls.
Contributors