import { type Effect } from "effector";
Effect is a container for async function or any throwing function.
It can be safely used in place of the original async function.
Methods
.use(handler)
Provides a function, which will be called when the effect is triggered.
Formulae
effect.use(fn);
- Set handler
fn
foreffect
- If effect already had an implementation at the time of the call, it will be replaced by a new one
Hint: current handler can be extracted with effect.use.getCurrent().
You must provide a handler either through .use method or handler
property in createEffect, otherwise effect will throw with no handler used in _%effect name%_
error when effect will be called.
Arguments
handler
(Function): Function, that receives the first argument passed to an effect call.
Returns
(Effect): The same effect
Examples
const fetchUserReposFx = createEffect();
fetchUserReposFx.use(async (params) => {
console.log("fetchUserReposFx called with", params);
const url = `https://api.github.com/users/${params.name}/repos`;
const req = await fetch(url);
return req.json();
});
fetchUserReposFx({ name: "zerobias" });
// => fetchUserRepos called with {name: 'zerobias'}
.use.getCurrent()
Returns current handler of effect. Useful for testing.
Formulae
fn = effect.use.getCurrent();
- Returns current handler
fn
foreffect
- If no handler was assigned to
effect
, default handler will be returned (that throws an error)
Hint: to set a new handler use effect.use(handler)
Returns
(Function): Current handler, defined by handler
property or via .use
call.
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
.watch(watcher)
Subscribe to effect calls.
Formulae
const unwatch = effect.watch(watcher);
- Call
watcher
on eacheffect
call, pass payload ofeffect
as argument towatcher
- When
unwatch
is called, stop callingwatcher
Arguments
watcher
(Watcher): A function that receivespayload
.
Returns
Subscription: Unsubscribe function.
Examples
import { createEffect } from "effector";
const fx = createEffect((params) => params);
fx.watch((params) => {
console.log("effect called with value", params);
});
await fx(10);
// => effect called with value 10
.prepend(fn)
Creates an event, upon trigger it sends transformed data into the source 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.
Formulae
const event = effect.prepend(fn);
- When
event
is triggered, callfn
with payload fromevent
, then triggereffect
with the result offn()
event
will haveEventCallable<T>
type, so can be used astarget
in methods likesample()
Arguments
fn
(Function): A function that receivespayload
, should be pure.
Returns
Event: New event.
.map(fn)
Creates a new event, which will be called after the original effect is called, applying the result of a fn
as a payload. It is a special function which allows you to decompose dataflow, extract or transform data.
Formulae
const second = first.map(fn);
- When
first
is triggered, pass payload fromfirst
tofn
- Trigger
second
with the result of thefn()
call as payload second
event will haveEvent<T>
type, so it CAN NOT be used astarget
in methods likesample()
Arguments
fn
(Function): A function that receivespayload
, should be pure.
Returns
Event: New event.
Examples
import { createEffect } from "effector";
const userUpdate = createEffect(({ name, role }) => {
console.log(name, role);
});
const userNameUpdated = userUpdate.map(({ name }) => name); // you may decompose dataflow with .map() method
const userRoleUpdated = userUpdate.map(({ role }) => role.toUpperCase()); // either way you can transform data
userNameUpdated.watch((name) => console.log(`User's name is [${name}] now`));
userRoleUpdated.watch((role) => console.log(`User's role is [${role}] now`));
await userUpdate({ name: "john", role: "admin" });
// => User's name is [john] now
// => User's role is [ADMIN] now
// => john admin
Properties
You are not supposed to use parts of effect (like .done
and .pending
) as a target
in sample (even though they are events and stores), since effect is a complete entity on its own. This behavior will not be supported.
In the examples below constant effect
has this signature:
effect: Effect<Params, Done, Fail>;
.done
Event
Event, which is triggered when handler is resolved.
Do not manually call this event. It is an event that depends on effect.
Formulae
effect.done: Event<{ params: Params; done: Done }>;
Properties
Event triggered with an object of params
and result
:
params
(Params): An argument passed to the effect callresult
(Done): A result of the resolved handler
Examples
import { createEffect } from "effector";
const fx = createEffect((value) => value + 1);
fx.done.watch(({ params, result }) => {
console.log("Call with params", params, "resolved with value", result);
});
await fx(2);
// => Call with params 2 resolved with value 3
.doneData
Event
Event, which is triggered by the result of the effect execution.
Do not manually call this event. It is an event that depends on the effect.
Formulae
effect.doneData: Event<Done>;
doneData
is an event, that triggered wheneffect
is successfully resolved withresult
from .done
Event triggered when handler is resolved.
Examples
import { createEffect } from "effector";
const fx = createEffect((value) => value + 1);
fx.doneData.watch((result) => {
console.log(`Effect was successfully resolved, returning ${result}`);
});
await fx(2);
// => Effect was successfully resolved, returning 3
.fail
Event
Event, which is triggered when handler is rejected or throws error.
Do not manually call this event. It is an event that depends on effect.
Formulae
effect.fail: Event<{ params: Params; error: Fail }>;
Properties
Event triggered with an object of params
and error
:
params
(Params): An argument passed to effect callerror
(Fail): An error caught from the handler
Examples
import { createEffect } from "effector";
const fx = createEffect(async (value) => {
throw Error(value - 1);
});
fx.fail.watch(({ params, error }) => {
console.log("Call with params", params, "rejected with error", error.message);
});
fx(2);
// => Call with params 2 rejected with error 1
.failData
Event
Event, which is triggered with error thrown by the effect.
Do not manually call this event. It is an event that depends on effect.
Formulae
effect.failData: Event<Fail>;
failData
is an event, that triggered wheneffect
is rejected witherror
from .fail
Event triggered when handler is rejected or throws error.
Examples
import { createEffect } from "effector";
const fx = createEffect(async (value) => {
throw Error(value - 1);
});
fx.failData.watch((error) => {
console.log(`Execution failed with error ${error.message}`);
});
fx(2);
// => Execution failed with error 1
.finally
Event
Event, which is triggered when handler is resolved, rejected or throws error.
Do not manually call this event. It is an event that depends on effect.
Properties
type Success = { status: 'done'; params: Params; result: Done }
type Failure = { status: 'fail'; params: Params; error: Fail }
effect.finally: Event<Success | Failure>;
Properties
Event, which is triggered with an object of status
, params
and error
or result
:
status
(string): A status of effect (done
orfail
)params
(Params): An argument passed to effect callerror
(Fail): An error caught from the handlerresult
(Done): A result of the resolved handler
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 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
.pending
Store
Store contains true
when effect is called but not resolved yet. Useful to show loaders.
Do not modify store value! It is derived store and should be in predictable state.
Formulae
effect.pending: Store<boolean>;
- Store will update when
done
orfail
are triggered - Store contains
true
value until the effect is resolved or rejected
Returns
DerivedStore: Store that represents current state of the effect
Examples
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 <div>{loading ? "Loading..." : "Load complete"}</div>;
};
ReactDOM.render(<Loading />, document.getElementById("root"));
fetchApiFx(3000);
It’s property is a shorthand for common use case:
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
Shows how many effect calls aren’t settled yet. Useful for rate limiting.
Do not modify $count
value! It is derived store and should be in predictable state.
Formulae
effect.inFlight: Store<number>;
- The store will be
0
if no calls ofeffect
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
DerivedStore: Store that represents count of the running effects
Examples
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
Types
import { type EffectParams, type EffectResult, type EffectError } from "effector";
EffectParams<FX>
Allows to extract type of Params from effect
.
const effect: Effect<Params, Done, Fail>;
type Params = EffectParams<typeof effect>;
EffectResult<FX>
Allows to extract type of result from effect
.
const effect: Effect<Params, Done, Fail>;
type Done = EffectResult<typeof effect>;
EffectError<FX>
Allows to extract type of error from effect
.
const effect: Effect<Params, Done, Fail>;
type Fail = EffectError<typeof effect>;