Списки
Простыми словами
Как выводить меняющиеся списки: Each узнаёт строки по ключу и переставляет готовые DOM-узлы вместо перерисовки всего списка.
<Each>: ключ — это личность строки
import { Each } from "@continuum-js/dom";
<ul>
<Each each={todos} by={(t) => t.id}>
{(t) => <TodoRow todo={t} />}
</Each>
</ul>;by играет роль key из React, но с более сильным следствием: на каждый ключ живёт одно построенное поддерево. Пока ключ присутствует в списке, его строка не перерендеривается — вообще. При изменении порядка DOM-узлы переставляются минимальным числом перемещений (LIS-алгоритм), фокус сохраняется.
Из этого следствия:
- строка строится один раз →
renderполучает элемент на момент появления ключа. Если содержимое строки должно меняться, внутрь нужно передавать State (см. ниже); - дубликаты ключей игнорируются (остаётся первый) — ключ обязан быть уникальным;
- удаление ключа из списка уничтожает поддерево строки каскадно: подписки, таймеры, вложенные регионы — всё убирается деревом владения.
Меняющееся содержимое строки
Если элементы списка обновляются «на месте» (тот же id, другие поля), прокидывайте в строку state её данных, а не снапшот:
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>;Строка построена один раз, а её текст и класс — живые привязки. Обновление поля патчит текстовый узел, не трогая структуру.
Фильтрация и сортировка — производные списки
Отфильтрованный список — это map над исходным, а не отдельное состояние:
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>;Переключение фильтра меняет состав ключей; строки, чьи ключи уцелели, переезжают без перерендера.
Когда <Each> не нужен
Статический список (данные не меняются за время жизни поддерева) — это обычный array.map прямо в JSX:
<ul>
{items.map((i) => (
<li>{i.name}</li>
))}
</ul><Each> нужен только когда список — State.
Незнакомый термин? Вся терминология этой документации объяснена в глоссарии.