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).
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 . |
done | Derived event that triggers when the effect completes successfully with params and result. |
doneData | Derived event with the result of successful effect execution with result. |
fail | Derived event that triggers when the effect execution fails with params and error. |
failData | Derived event with the effect’s error data. |
finally | Derived event that triggers on any effect completion. |
pending | Derived store Store<boolean> with the effect execution status (true during execution). |
inFlight | Derived store Store<number> with the count of active effect calls. |
sid | Unique identifier of the unit. |
shortName | String property containing the variable name in which the effect was declared. |
compositeName | Composite effect name (including domain and short name) — useful for logging and tracing. |
Effect Peculiarities
- When called imperatively, they always return a promise reflecting the side effect execution progress.
- Effects accept only one argument, just like events.
- They have built-in stores (
pending
,inFlight
) and events (done
,fail
,finally
, etc.) for convenience.
Effect Methods
.use(handler)
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.
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
- 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
- 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
- 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
- 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
.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
.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
.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
.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
.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
.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
.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"
// ]
// }
Related API and Articles
- API
createEffect
- Creating a new effectEvent API
- Description of events, their methods and propertiesStore API
- Description of stores, their methods and propertiessample
- Key operator for building connections between unitsattach
- Creates new effects based on other effects
- Articles