Keep SolidJS Signals Outside the Component Body
Defining createSignal inside a SolidJS component resets state on every render. Declare signals at module level instead.
12 Jan 2026, 11:12 UTC

The problem: a signal created inside a component resets on every render
In SolidJS, a component function can run more than once. If you call createSignal inside that function, the signal initializes to its starting value on every run. Any state held in that signal is lost, and the UI stops reflecting updates.
Useful takeaway: declare signals outside the component body—typically at module level—and read them in JSX. Only the component's JSX should read the signal; never create it there.
Worked example: a counter that loses its value
This version defines the signal inside the component:
import { createSignal } from "solid-js";
function BrokenCounter() {
// Resets to 0 whenever this component function re-runs.
const [count, setCount] = createSignal(0);
return (
setCount(c => c + 1)}>
{count()}
);
}
If a parent re-renders this component, count goes back to 0. The user's clicks are effectively discarded because the signal instance and its value are recreated.
Moving the signal outside the component fixes it:
import { createSignal } from "solid-js";
// Created once, outside the render phase.
const [count, setCount] = createSignal(0);
function FixedCounter() {
return (
setCount(c => c + 1)}>
{count()}
);
}
Now every render reads the same signal instance. SolidJS registers the read as a dependency and updates only the text node when setCount runs.
How the mechanism works
A signal is a mutable primitive wrapped in a getter and setter. When a function such as a component's JSX expression reads count(), SolidJS records that function as a subscriber. When setCount changes the value, SolidJS re-executes only the tracked subscribers instead of re-running the whole component. This is fine-grained reactivity: the unit of update is the individual DOM node, not the component tree.
Reading the signal without calling it is a common mistake. In JSX, {count} passes the signal function itself rather than its current value. No dependency is registered, and the rendered output is not the number you expect.
Limits and common mistakes
- Do not create signals in JSX. An expression like
<div>{createSignal(0)[0]()}</div>builds a new signal on every render and discards the previous one immediately. - Do not mutate nested values in place. If the signal holds an object or array, replace the value with a new object instead of pushing or assigning into the existing one.
- Avoid circular computed dependencies. A
computedthat writes to a signal it reads can create an update loop. Derive values from signals; do not write back to the same signal inside the derivation. - Do not treat signals as plain variables. Always call the getter (
count()) and use the setter (setCount(...)) to update.
How to verify the fix
- Open the browser developer tools and inspect the button element.
- Click the button several times.
- Confirm that only the text node inside the button changes; the surrounding element and sibling components should not re-render.
- If the text resets or stays the same, check whether
createSignalis inside the component function. Move it to module level and reload.
You can also inspect the compiled JavaScript. Signal reads appear as function calls wrapped in tracking logic rather than direct property access. Exact output depends on your build tool and SolidJS version.
Version assumptions
This guide assumes SolidJS 1.x, where createSignal and computed are the standard reactive primitives. APIs may differ in major releases.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.