Effect API

import { type Effect, createEffect } from "effector";

const effectFx = createEffect();

An Effect is a unit designed to handle side effects, whether synchronous or asynchronous. It includes a set of pre-built events and stores that streamline common operations. It is categorized as a unit.

Effects can be called like regular functions (imperative call) and can also be connected along with their properties to various API methods including sample and split (declarative connection).

effective effect

If you’re not familiar with effects and how to work with them, check out Asynchronous Operations in effector using Effects.

Effect Interface

Available methods and properties of effects:

Method/Property
Description
use(handler)Replaces the effect’s handler with a new handler function.
use.getCurrent()Returns the current effect handler.
watch(watcher)Adds a listener that calls watcher on each effect invocation.
map(fn)Creates a new derived event with the result of calling fn on the effect’s parameters.
prepend(fn)Creates a new event that transforms input data through fn before calling the effect.
filterMap(fn)Creates a new derived event that triggers with the result of fn if it doesn’t return undefined.
doneDerived event that triggers when the effect completes successfully with params and result.
doneDataDerived event with the result of successful effect execution with result.
failDerived event that triggers when the effect execution fails with params and error.
failDataDerived event with the effect’s error data.
finallyDerived event that triggers on any effect completion.
pendingDerived store Store<boolean> with the effect execution status (true during execution).
inFlightDerived store Store<number> with the count of active effect calls.
sidUnique identifier of the unit.
shortNameString property containing the variable name in which the effect was declared.
compositeNameComposite effect name (including domain and short name) — useful for logging and tracing.

Effect Peculiarities

  1. When called imperatively, they always return a promise reflecting the side effect execution progress.
  2. Effects accept only one argument, just like events.
  3. They have built-in stores (pending, inFlight) and events (done, fail, finally, etc.) for convenience.

Effect Methods

.use(handler)

use is an anti-pattern

If the implementation value is known immediately, it’s better to use createEffect(handler).

The use(handler) method is an anti-pattern that degrades type inference.

Defines the effect implementation: the function that will be called when the effect is triggered. Used for cases when the implementation is not set during creation or when testing requires changing the effect’s behavior.
Accepts a params argument, which is the data with which the effect was called.

use takes priority

If the effect already had an implementation at the time of call, it will be replaced with the new one.

  • Formula
const fx: Effect<Params, Done>;
fx.use(handler);
  • Type
effect.use(handler: (params: Params) => Promise<Done> | Done): Effect<
  Params,
  Done,
  Fail
>
  • Examples
import { createEffect } from "effector";

const fetchUserReposFx = createEffect();

fetchUserReposFx.use(async ({ name }) => {
  console.log("fetchUserReposFx called for github user", name);

  const url = `https://api.github.com/users/${name}/repos`;
  const req = await fetch(url);
  return req.json();
});

await fetchUserReposFx({ name: "zerobias" });
// => fetchUserReposFx called for github user zerobias

Run example

  • Return value

Returns the current effect.


.use.getCurrent()

Method for getting the current effect implementation. Used for testing.

If the effect doesn’t have an implementation set yet, a default function will be returned that throws an error when called.

  • Formula
const fx: Effect<Params, Done>;
const handler = fx.use.getCurrent();
  • Type
effect.use.getCurrent(): (params: Params) => Promise<Done>
  • Examples
const handlerA = () => "A";
const handlerB = () => "B";

const fx = createEffect(handlerA);

console.log(fx.use.getCurrent() === handlerA);
// => true

fx.use(handlerB);
console.log(fx.use.getCurrent() === handlerB);
// => true

Run example

  • Return value

Returns the effect’s implementation function that was set through createEffect or using the use method.


.watch(watcher)

Calls an additional function with side effects on each effect trigger. Shouldn’t be used for logic, better to replace with sample.

  • Formula
const fx: Effect<Params, Done>;
const unwatch = fx.watch(watcher);
  • Type
effect.watch(watcher: (payload: Params) => any): Subscription
  • Examples
import { createEffect } from "effector";

const fx = createEffect((params) => params);

fx.watch((params) => {
  console.log("effect called with argument", params);
});

await fx(10);
// => effect called with argument 10

Run example

  • Return value

Subscription cancellation function, after calling it the watcher stops receiving updates and is removed from memory.


.map(fn)

Creates a derived event based on effect data. Works similarly to Event.map(fn).

  • Formula
const fx: Effect<Params, Done>;
const eventB = fx.map(fn);
  • Type
effect.map<T>(fn: (params: Params) => T): Event<T>
  • Examples
import { createEffect } from "effector";

const updateUserFx = createEffect(({ name, role }) => {
  // ...
});

const userNameUpdate = updateUserFx.map(({ name }) => name);
const userRoleUpdate = updateUserFx.map(({ role }) => role.toUpperCase());

userNameUpdate.watch((name) => {
  console.log(`Started changing user name to ${name}`);
});
userRoleUpdate.watch((role) => {
  console.log(`Started changing user role to ${role}`);
});

await updateUserFx({ name: "john", role: "admin" });
// => Started changing user name to john
// => Started changing user role to ADMIN

Run example

  • Return value

Returns a new derived event.


.prepend(fn)

Creates a new event to transform data before running the effect. Compared to map, it works in the opposite direction. Works similarly to Event.prepend(fn).

  • Formula
const fx: Effect<Params, Done>;
const trigger = fx.prepend(fn);
  • Type
effect.prepend<Before>(fn: (_: Before) => Params): EventCallable<Before>
  • Examples
import { createEffect } from "effector";

const saveFx = createEffect(async (data) => {
  console.log("saveFx called with:", data);
  await api.save(data);
});

// create a trigger event for the effect
const saveForm = saveFx.prepend((form) => ({
  ...form,
  modified: true,
}));

saveForm({ name: "John", email: "john@example.com" });
// => saveFx called with: { name: "John", email: "john@example.com", modified: true }
  • Return value

Returns a new event.


.filterMap(fn)

Creates a derived event that triggers with the result of fn if it doesn’t return undefined.

  • Formula
const fx: Effect<Params, Done>;
const filtered = fx.filterMap(fn);
  • Type
effect.filterMap<T>(fn: (payload: Params) => T | undefined): Event<T>
  • Examples
import { createEffect } from "effector";

const fetchUserFx = createEffect(async (id) => {
  const user = await api.getUser(id);
  return user;
});

const adminUserFetched = fetchUserFx.filterMap((user) => {
  if (user.role === "admin") {
    return user;
  }
  return undefined;
});

adminUserFetched.watch((admin) => {
  console.log("Admin loaded:", admin.name);
});

await fetchUserFx(1); // regular user - event won't trigger
await fetchUserFx(2); // admin
// => Admin loaded: John
  • Return value

Returns a new derived event.

Effect Properties

.done

Derived event that triggers with the result of effect execution and the argument passed during the call.

  • Type
interface Effect<Params, Done> {
  done: Event<{ params: Params; result: Done }>;
}
  • Examples
import { createEffect } from "effector";

const fx = createEffect((value) => value + 1);

fx.done.watch(({ params, result }) => {
  console.log("Call with argument", params, "completed with value", result);
});

await fx(2);
// => Call with argument 2 completed with value 3

Run example.


.doneData

Derived event that triggers with the result of successful effect execution.

  • Type
interface Effect<any, Done> {
  doneData: Event<Done>;
}
  • Examples
import { createEffect } from "effector";

const fx = createEffect((value) => value + 1);

fx.doneData.watch((result) => {
  console.log(`Effect completed successfully, returning ${result}`);
});

await fx(2);
// => Effect completed successfully, returning 3

Run example.


.fail

Derived event that triggers with the error that occurred during effect execution and the argument passed during the call.

  • Type
interface Effect<Params, any, Fail> {
  fail: Event<{ params: Params; error: Fail }>;
}
  • Examples
import { createEffect } from "effector";

const fx = createEffect(async (value) => {
  throw Error(value - 1);
});

fx.fail.watch(({ params, error }) => {
  console.log("Call with argument", params, "failed with error", error.message);
});

fx(2);
// => Call with argument 2 failed with error 1

Run example.


.failData

Derived event that triggers with the error that occurred during effect execution.

  • Type
interface Effect<any, any, Fail> {
  failData: Event<Fail>;
}
  • Examples
import { createEffect } from "effector";

const fx = createEffect(async (value) => {
  throw Error(value - 1);
});

fx.failData.watch((error) => {
  console.log(`Call failed with error ${error.message}`);
});

fx(2);
// => Call failed with error 1

Run example.


.finally

Derived event that triggers on both success and failure of effect completion with detailed information about arguments, results, and execution status.

  • Type
interface Effect<Params, Done, Fail> {
  finally: Event<
    | {
        status: "done";
        params: Params;
        result: Done;
      }
    | {
        status: "fail";
        params: Params;
        error: Fail;
      }
  >;
}
  • Examples
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 argument", value.params, "completed with value", value.result);
      break;
    case "fail":
      console.log("Call with argument", value.params, "failed with error", value.error.message);
      break;
  }
});

await fetchApiFx({ time: 100, ok: true });
// => Call with argument {time: 100, ok: true} completed with value 100 ms

fetchApiFx({ time: 100, ok: false });
// => Call with argument {time: 100, ok: false} failed with error 100 ms

Run example.


.pending

Derived store that shows whether the effect is currently executing.

  • Type
interface Effect<any, any> {
  pending: Store<boolean>;
}
  • Detailed description

This property eliminates the need to write code like this:

const $isRequestPending = createStore(false)
  .on(requestFx, () => true)
  .on(requestFx.done, () => false)
  .on(requestFx.fail, () => false);
  • Examples
import React from "react";
import { createEffect } from "effector";
import { useUnit } from "effector-react";

const fetchApiFx = createEffect(async (ms) => {
  await new Promise((resolve) => setTimeout(resolve, ms));
});

fetchApiFx.pending.watch(console.log);
// => false

const App = () => {
  const loading = useUnit(fetchApiFx.pending);
  return <div>{loading ? "Loading..." : "Loading complete"}</div>;
};

fetchApiFx(1000);
// => true
// => false

Run example.


.inFlight

Derived store that shows the number of running effects that are currently executing. Can be used to limit the number of concurrent requests.

  • Type
interface Effect<any, any> {
  inFlight: Store<number>;
}
  • Detailed description

This property eliminates the need to write code like this:

const $requestsInFlight = createStore(0)
  .on(requestFx, (n) => n + 1)
  .on(requestFx.done, (n) => n - 1)
  .on(requestFx.fail, (n) => n - 1);
  • Examples
import { createEffect } from "effector";

const fx = createEffect(async () => {
  await new Promise((resolve) => setTimeout(resolve, 500));
});

fx.inFlight.watch((amount) => {
  console.log("requests in flight:", amount);
});
// => requests in flight: 0

const req1 = fx();
// => requests in flight: 1

const req2 = fx();
// => requests in flight: 2

await Promise.all([req1, req2]);

// => requests in flight: 1
// => requests in flight: 0

Run example.


.sid

Unique unit identifier. It’s important to note that SID doesn’t change on each application run, it’s statically written into your application bundle for absolute unit identification. Set automatically through Babel plugin.

  • Type
interface Effect<any, any> {
  sid: string | null;
}

.shortName

String property containing the variable name in which the effect was declared. Effect name. Set either explicitly through the name field in createEffect, or automatically through babel plugin.

  • Type
interface Effect<any, any> {
  shortName: string;
}

.compositeName

Composite effect name (including domain and short name) — useful for logging and tracing.

  • Type
interface Effect<any, any> {
  compositeName: {
    shortName: string;
    fullName: string;
    path: Array<string>;
  };
}
  • Examples
import { createEffect, createDomain } from "effector";

const first = createEffect();
const domain = createDomain();
const second = domain.createEffect();

console.log(first.compositeName);
// {
//     "shortName": "first",
//     "fullName": "first",
//     "path": [
//         "first"
//      ]
// }

console.log(second.compositeName);
// {
//     "shortName": "second",
//     "fullName": "domain/second",
//     "path": [
//         "domain",
//         "second"
//      ]
// }
Contributors