Derived State in SolidJS: Why Your Filtered List Stays Static
SolidJS components run once. Learn how createMemo tracks signal dependencies so derived lists update automatically instead of staying stuck on the first render.
29 Apr 2026, 02:26 UTC

The problem: a filtered list that never filters
You add a search input to a SolidJS list. Inside the component, you read the search signal and filter the items array. The first render shows the right results, but typing in the input changes nothing. The list stays frozen on the initial data.
The useful takeaway is simple: SolidJS component functions run once. Code in the body executes at mount and does not re-run when signals change. To build derived state that follows its sources, you need createMemo.
Why the component body is not enough
In SolidJS, JSX is compiled to fine-grained DOM instructions, not a virtual DOM tree that re-renders on every state change. The component function itself executes a single time. If you write this:
const filtered = items().filter((item) =>
item.text.includes(query())
);
...items() and query() are read once. The result is a plain JavaScript array. Later changes to query do not re-run the body, so filtered never changes. Reading a signal inside the body subscribes that read, but the surrounding expression is still evaluated only at mount.
Use createMemo for derived state
createMemo returns a getter, just like createSignal. The function you pass runs when any signal it reads changes, and it caches the result until then. Solid tracks which signals were read during the computation, so only those dependencies trigger a recompute.
This is useful for expensive derivations such as filtered or sorted lists. The memo updates the value, and Solid updates only the DOM nodes that read the memo.
Worked example: a searchable todo list
Run this in a SolidJS 1.x project created with Vite or your preferred dev server:
import { createSignal, createMemo, For } from 'solid-js';
export default function App() {
const [query, setQuery] = createSignal('');
const [items, setItems] = createSignal([
{ id: 1, text: 'Learn SolidJS' },
{ id: 2, text: 'Build a project' },
{ id: 3, text: 'Deploy to production' },
]);
const filtered = createMemo(() => {
const q = query().toLowerCase();
return items().filter((item) =>
item.text.toLowerCase().includes(q)
);
});
return (
Search
setQuery(event.currentTarget.value)}
/>
{(item) => - {item.text}
}
);
}
query() and items() are read inside createMemo, so both signals become dependencies. When the user types, query changes, the memo recomputes, and the For block updates only the matching list items. The component body itself does not run again.
Diagnostic: confirm the body runs once
Add temporary logs to verify the behavior in your browser:
console.log('component body ran'); // appears once on load
const filtered = createMemo(() => {
console.log('memo recomputed'); // appears on mount and on dependency change
return items().filter(...);
});
Open the page, type in the search box, and watch the console. The body log should not repeat. The memo log should appear only when query or items changes. If you update an unrelated signal, the memo should not re-run.
Where to run: your project's terminal, with the dev server started (for example, npm run dev). Required permissions: none beyond normal file access. Risk: none; this is read-only diagnostic logging.
Trade-off: do not memoize everything
Wrapping a cheap calculation in createMemo adds tracking overhead that can exceed the cost of recomputing the value. Use it for genuinely expensive derivations, and measure first. Also, mutating a nested property inside an object stored in a signal may not be deeply tracked; replace the whole value or use Solid stores for fine-grained object reactivity.
How to verify the result
Open your browser's inspector, type in the search input, and confirm only the list nodes change while the input and surrounding markup stay stable. You can also check package.json to confirm you are on SolidJS 1.x, where these APIs are stable.
Closing
If a derived value in SolidJS does not update when its source signal changes, the computation is probably running once in the component body. Move it into createMemo, read the signals inside the memo function, and let Solid track the dependencies automatically.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.