Effects with createEffect
Running side effects in response to signal changes, and how automatic dependency tracking differs from React's dependency arrays.
읽는 데 2분
Signals and memos describe values. createEffect is for side effects — anything that reaches outside Solid's reactive system, like logging, updating document.title, writing to localStorage, or manually touching the DOM.
Basic usage
import { createSignal, createEffect } from "solid-js";
function TitleUpdater() {
const [count, setCount] = createSignal(0);
createEffect(() => {
document.title = `Clicked ${count()} times`;
});
return <button onClick={() => setCount(count() + 1)}>Click me</button>;
}The function passed to createEffect runs once immediately (to establish its dependencies and produce the initial effect), and then re-runs automatically whenever any signal it read during that run changes. Here, it reads count(), so it re-runs on every click.
No dependency array — and no need for one
If you've used React's useEffect, the obvious question is: where's the dependency array? Solid doesn't have one, and it isn't optional syntax you can forget — it doesn't exist because it isn't needed. Solid tracks dependencies automatically by recording every signal read during the effect's execution. There's no equivalent of a stale-closure bug from a missing dependency, and no lint rule needed to catch one, because the tracking isn't something you declare — it's observed directly from what the function actually reads.
createEffect(() => {
if (isEnabled()) {
console.log("Value is:", value());
}
});This effect only depends on value() when isEnabled() is true — because that's the only branch where it's actually read. If isEnabled() becomes false, the effect still re-runs (it depends on isEnabled), but it stops depending on value until the branch is taken again. Dependencies are re-evaluated fresh on every run, not fixed at first render.
Cleaning up after an effect
Effects that set up something ongoing — a timer, a subscription, an event listener — should clean it up before the next run, using onCleanup inside the effect:
import { createEffect, onCleanup } from "solid-js";
createEffect(() => {
const id = setInterval(() => console.log(count()), 1000);
onCleanup(() => clearInterval(id));
});onCleanup registers a function that runs right before the effect re-executes, and again when the owning component is disposed entirely. This mirrors the cleanup function you'd return from a React useEffect — same purpose, different API shape.
Effects vs memos: pick based on intent
A common mix-up: using createEffect to compute a value and store it in another signal, when createMemo already does that more directly.
// Awkward — an effect standing in for a derived value
const [doubled, setDoubled] = createSignal(0);
createEffect(() => setDoubled(count() * 2));
// Direct — this is exactly what createMemo is for
const doubled = createMemo(() => count() * 2);If you're computing a value from other reactive state, reach for createMemo (or a plain derived function). Reserve createEffect for genuine side effects — things that happen because a value changed, rather than things that are a value.