Atomico — библиотека для создания веб-компонентов на JavaScript с реактивным подходом. Работа со списками и управление ключами является важной частью оптимизации рендеринга и поддержания согласованного состояния компонентов.
Списки в Atomico создаются с помощью функции map,
которая используется внутри JSX-подобного синтаксиса. Основная цель —
корректно отображать массив данных в DOM без потери реактивности.
Пример базового рендеринга списка:
import { c, useState } from "atomico";
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "Купить хлеб" },
{ id: 2, text: "Помыть машину" },
{ id: 3, text: "Позвонить другу" }
]);
return (
<host>
<ul>
{todos.map(todo => (
<li>{todo.text}</li>
))}
</ul>
</host>
);
}
export const todoList = c(TodoList);
В этом примере каждый элемент массива todos отображается
как <li>. Однако при обновлении массива порядок
элементов может изменяться, и без явного указания ключей Atomico будет
вынужден пересоздавать все элементы, что снижает производительность и
может привести к потере состояния вложенных компонентов.
Ключ (key) — это уникальный идентификатор элемента
списка, который позволяет Atomico отслеживать его между рендерами. Ключи
обеспечивают:
<input> с пользовательским вводом, без ключа значение
может сбрасываться при изменении массива.Правильное использование ключей:
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
Важно: ключи должны быть уникальными среди элементов текущего списка, стабильными между рендерами и не использовать случайные значения вроде индекса массива, если элементы могут переставляться.
Использование индекса допустимо только в случаях, когда порядок элементов никогда не меняется и элементы не добавляются/удаляются динамически:
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo.text}</li>
))}
</ul>
Однако при динамическом обновлении списка это может привести к неожиданному поведению, например:
Atomico использует реактивные хуки, такие как useState,
для управления массивами данных. При добавлении, удалении или изменении
элементов необходимо создавать новый массив, чтобы реактивность
сработала корректно.
Пример добавления элемента:
function addTodo() {
setTodos([...todos, { id: Date.now(), text: "Новый пункт" }]);
}
Пример удаления элемента:
function removeTodo(id) {
setTodos(todos.filter(todo => todo.id !== id));
}
Пример обновления текста:
function updateTodo(id, newText) {
setTodos(todos.map(todo => todo.id === id ? { ...todo, text: newText } : todo));
}
В каждом случае используется новый массив, что гарантирует корректное срабатывание реактивного рендера Atomico.
При работе с вложенными списками ключи необходимо задавать для каждого уровня:
const categories = [
{ id: 1, name: "Фрукты", items: ["Яблоко", "Банан"] },
{ id: 2, name: "Овощи", items: ["Морковь", "Помидор"] }
];
<ul>
{categories.map(cat => (
<li key={cat.id}>
{cat.name}
<ul>
{cat.items.map((item, idx) => (
<li key={idx}>{item}</li>
))}
</ul>
</li>
))}
</ul>
Для вложенного списка индексы допустимы только если порядок элементов фиксирован. Для динамических вложенных данных лучше использовать уникальные идентификаторы.
Эти правила позволяют поддерживать высокую производительность и предсказуемое поведение компонентов при работе с динамическими массивами данных.