Declaring side effects
Not all logic fits into pure computation. Sometimes you need to log something, start a timer, subscribe to an external source, or clean up resources when they are no longer needed.
Reago provides tools for running side effects when atoms mount, unmount, or recompute. In this article, you will learn how to hook into the atom lifecycle to perform this kind of work safely.
Computation effects
Computation effects are side effects that run after a computation finishes.
In addition to the side effect itself, they might optionally provide a cleanup function that will run when the side effect is about to be replaced with another.
import {atomComputationEffect} from 'reago';
function $atom() {
atomComputationEffect(() => {
console.log('I will run after each computation');
return () => {
console.log('I will cleanup after this side effect, when a new computation finishes');
};
});
}
In addition to the effect logic itself, atomComputationEffect
optionally accepts a second argument: the list of dependencies
. You should already be familiar with the concept - we declared them for atomMemo
.
To reiterate, for atomComputationEffect
specifically:
- If you do not provide
dependencies
at all, like in the example above, the effect will run for each computation. Reago will first run the cleanup function from the previous computation, and then thesetup
from the new computation. - If you provide an empty
dependencies
array, Reago will runsetup
only for the first computation. The cleanup function will run only if the store or the atom itself is destroyed. - If you provide a list of
dependencies
, Reago will run thesetup
function for the first computation, and then on subsequent computations, it will run the old cleanup and the newsetup
only ifdependencies
changed.
Let us dive into a more practical example. Imagine a boolean toggle that will automatically turn itself off after a few seconds. It is a bit like the "useless box" design that once circulated the internet.

We can build an atom that declares a boolean state variable, and an additional computation effect that will automatically turn it off via setTimeout
.
import {atomState, atomComputationEffect} from 'reago';
function $uselessBox() {
const [value, setValue] = atomState(false);
atomComputationEffect(() => {
if (value) {
const timeout = setTimeout(() => {
setValue(false);
}, 1000);
return () => clearTimeout(timeout);
}
}, [value]);
return value;
}
Notice how we added value
to the list of dependencies
- it will ensure the setTimeout
is cancelled if someone turns the switch off manually before the hardcoded delay.
Mount effects
Mount effects are a different type of side effects that run when an atom is mounted or unmounted.
Do you remember?
An atom is mounted when it is subscribed to, and unmounted when there are no subscribers left.
The syntax is almost identical to computation effects. You provide a setup method, an optional cleanup method, and a list of dependencies, which in this case is mandatory.
import {atomMountEffect} from 'reago';
function $atom() {
atomMountEffect(() => {
console.log('I will run when $atom is mounted');
return () => {
console.log('I will run when $atom is unmounted');
};
}, []);
}
Tip
In practice, you will be using mount effects very rarely, as your atoms should support one-off reads too. Most use cases are more suitable for computation effects, or the invalidation pattern, which you are going to learn about in the next article.
Hierarchy of side effects
Our examples were based on simple atoms, but real-life apps are much more complex than that. Multiple effects, multiple types of effects, complex dependency graphs - what happens then?
Computation effects before mount effects
If an atom defines both types of side effects, computation effects run before mount effects.
Effects are set-up in the order of appearance
If an atom defines multiple side effects of the same type, they will run in the order they appear in your code.
Effects are cleaned up in reverse order
If an atom defines multiple side effects of the same type, and they provide cleanup functions, the cleanup functions will run in the reverse order atoms were set up. In other words: last to run, first to clean-up.
Effects are set-up from the bottom
If
$atom1
reads$atom2
, effects of$atom2
will take precedence over effects of$atom1
.However, the cleanup will happen in reverse. First
$atom1
and then$atom2
.
Further reading
We get it - effects might be confusing at first. If you want to dive deeper or just double-check the specifics, take a look at the full API documentation for each effect type. It includes usage patterns, argument signatures, and additional examples.