SolidJS: Why <For> and <Show> Beat .map() and Ternaries for Reactive Lists and Conditionals
SolidJS’s <For> and <Show> components keep reactive lists and conditionals in sync without re‑running the parent component. Learn why they outperform plain .map() and ternary expressions and how to use them correctly.
23 Aug 2025, 11:52 UTC

Problem: Reactive lists and conditionals that don’t update
When you build a UI with SolidJS you often start by rendering an array or a conditional branch with plain JavaScript inside JSX:
const [items, setItems] = createSignal([]);
return (
{items().map(item => {item.name})}
);
That looks fine at first glance, but it only runs once. The JSX compiler turns the .map() call into a static list of DOM nodes. When items changes the parent component is not re‑executed, so the new elements are never rendered. The same problem happens with ternary operators for conditionals – the branch that was not rendered stays disposed, but any stale closures or untracked signals can leak.
Thesis: Use SolidJS’s and primitives for reactive lists and conditionals
SolidJS ships two control‑flow components that are compiled into fine‑grained DOM instructions. They watch the signals you pass and update the DOM efficiently without re‑running the parent component. <For> keeps an array in sync, inserting, removing, or moving nodes as needed. <Show> mounts or unmounts a branch based on a reactive predicate, preventing stale closures and unnecessary DOM nodes.
Section 1 – for reactive arrays
To render a dynamic list you should write:
import { For, createSignal } from "solid-js";
const [list, setList] = createSignal([{id:1, name:'Alpha'}, {id:2, name:'Beta'}]);
function addItem() {
setList(l => [...l, {id: Date.now(), name: 'New'}]);
}
return (
item.id}>
{item => {item.name}}
Add
);
Key points:
each={list()}passes the current array value. Thekeyprop tells Solid how to identify items across updates. Use a stable identifier; don’t use the array index.- When
addItempushes a new element, Solid inserts a single new node, leaving existing nodes untouched. The parent component function does not re‑run. - For pure static lists you can skip
<For>and use.map()– the overhead is negligible, and you avoid the extra abstraction.
Potential pitfalls:
- Directly mutating the array (e.g.,
list().push()) can break tracking. UsesetList(l => [...l, newItem])orcreateMutablefromsolid-js/storeif you need in‑place updates. - Using the array index as
keycauses state to stick to the wrong item after reordering. Always supply a unique id.
Section 2 – for conditionals
Instead of a ternary expression, wrap the branch you want to toggle with <Show>:
import { Show, createSignal } from "solid-js";
const [visible, setVisible] = createSignal(false);
return (
This content is only mounted when visible is true
setVisible(v => !v)}>Toggle
);
Benefits:
- When
visibleis false, the branch is completely disposed. No stale closures, no lingering event listeners, and no hidden DOM nodes. - When the condition flips back, the branch is re‑mounted from scratch, so any local state inside it is reset – often the desired behaviour for modal dialogs, forms, etc.
- Using a ternary inside JSX can accidentally keep the hidden branch in memory, leading to memory leaks or stale references.
Section 3 – Trade‑offs and limitations
| Aspect | Control‑flow (/) | Plain JSX (.map(), ternary) |
|---|---|---|
| Reactivity | Fine‑grained; updates only affected nodes | Whole component re‑runs; may re‑create DOM unnecessarily |
| Complexity | Requires key function for lists | No extra boilerplate |
| Server‑Side Rendering | Hydration must match client rendering; may need special handling | Simpler hydration but less efficient updates |
| Mutable arrays | Breaking change if you mutate directly; use createMutable or solid-js/store | Direct mutation works but may lead to stale UI |
| Static lists | Overhead of control‑flow; but still fine | Shortest code |
Actionable Checklist
- Use
<For>when you need a list that can add, remove, or reorder items reactively. - Always provide a stable
key(e.g., a database ID). Avoid array index keys. - Use
<Show>for branches that should be fully mounted/unmounted based on a reactive flag. - If you only ever render a static array, plain
.map()is fine. - When mutating arrays in place, switch to
createMutableorsolid-js/storeto keep<For>tracking intact. - Verify that your updates cause only the expected DOM changes by inspecting the element tree after state changes.
Conclusion
SolidJS’s <For> and <Show> are small, well‑tested primitives that solve the most common pitfalls of reactive lists and conditionals. They keep the DOM in sync with signals without re‑executing parent components, prevent stale closures, and give you fine‑grained control over element lifecycle. Adopt them for any dynamic UI and keep plain .map() and ternaries for truly static fragments.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.