Skip to main content

Effects

Create Effects​

Effects are functions that are executed when a signal changes. You can use useEffect() to create an effect:

import { useSignal, useEffect } from "sinho";

const [value, setValue] = useSignal(0);

useEffect(() => {
console.log(value());
});

Inside of components, the function is first called when the component mounts, otherwise it is called immediately on creation.

The effect can track all its accessed signals and will be re-executed whenever one of them changes, in this case value.

Manage Dependencies​

You can also specify dependencies manually by specifying an array of dependencies as the second argument of useEffect:

const [name, setName] = useSignal("Jane");
const [gender, setGender] = useSignal("female");

useEffect(() => {
console.log(name(), gender());
}, [name]);

In this example, the effect will only be re-executed when name changes. You can also use signal.peek() to access the value of a signal without tracking, so the sample above is equivalent to:

useEffect(() => {
console.log(name(), gender.peek());
});

Clean Up Effects​

It is possible to return a cleanup function that will be run when the effect is re-executed or destroyed:

useEffect(() => {
console.log("Hello ", name());

return () => {
console.log("Goodbye ", name());
};
});

In this case, whenever name is about to change, the cleanup function will be executed first.

Batching Updates​

Say, we have an effect which depends on multiple signals:

const [name, setName] = useSignal("Jane");
const [gender, setGender] = useSignal("female");

useEffect(() => {
console.log(name(), gender());
});

If both signals change independently, the effect will be executed twice:

setName("John");
// Effect will print "John female"
setGender("male");
// Effect will print "John male"

To avoid this, you can batch updates using useBatch:

import { useBatch } from "sinho";

useBatch(() => {
setName("John");
setGender("male");
});
// Effect will print "John male"

This way, the effect will only be executed once after all signals have changed.

In fact, all updates to signals inside of effects and event listeners will be batched by default. This is to prevent unnecessary re-renders and to improve performance, but also to ensure that all signals are in a consistent state when the effect is executed.

To manually ensure the effects are executed immediately inside an effect or event listener, you can also use flushBatch:

import { useEffect, flushBatch } from "sinho";

useEffect(() => {
setName("Charlie");
setGender("nonbinary");
flushBatch();

console.log(name(), gender()); // Prints "Charlie nonbinary"
});