List rendering
In plain words
Rendering changing lists: Each recognizes rows by key and moves ready-made DOM nodes instead of repainting the list.
<Each>: the key is the row's identity
import { Each } from "@continuum-js/dom";
<ul>
<Each each={todos} by={(t) => t.id}>
{(t) => <TodoRow todo={t} />}
</Each>
</ul>;by plays the role of React's key, with a stronger consequence: there is one live subtree per key. As long as a key is present in the list, its row is never re-rendered — at all. When the order changes, DOM nodes are reordered with a minimal number of moves (the LIS algorithm), and focus is preserved.
What follows from this:
- a row is built once →
renderreceives the item as of the key's appearance. If the row's content must change, pass a State inside (see below); - duplicate keys are ignored (the first wins) — keys must be unique;
- removing a key destroys the row's subtree in a cascade: subscriptions, timers, nested regions — the ownership tree cleans it all up.
Row content that changes
If list items update "in place" (same id, different fields), pass the row a state of its data, not a snapshot:
function TodoRow(props: { todo: State<Todo> }) {
const done = props.todo.map((t) => t.done);
const text = props.todo.map((t) => t.text);
return <li class={done.map((d) => (d ? "done" : ""))}>{text}</li>;
}
<Each each={todos} by={(t) => t.id}>
{(t) => (
<TodoRow todo={todos.map((xs) => xs.find((x) => x.id === t.id) ?? t)} />
)}
</Each>;The row is built once, while its text and class are live bindings. A field update patches a text node without touching the structure.
Filtering and sorting are derived lists
A filtered list is a map over the source, not separate state:
const visible = combine(todos, filter, (xs, f) =>
f === "all" ? xs : xs.filter((t) => t.done === (f === "done")),
);
<Each each={visible} by={(t) => t.id}>{(t) => <TodoRow …/>}</Each>;Switching the filter changes the set of keys; rows whose keys survive move without a re-render.
When you don't need <Each>
A static list (data never changes during the subtree's life) is a plain array.map right in JSX:
<ul>
{items.map((i) => (
<li>{i.name}</li>
))}
</ul><Each> is only for lists that are States.
Unfamiliar term? Every piece of jargon in these docs is explained in the glossary.