Директива repeat

Директива repeat в FAST Element обеспечивает высокопроизводительное рендеринг-повторение коллекций данных в шаблонах. Директива связывает массив данных и разметку, автоматически добавляя, обновляя и удаляя DOM-элементы при изменении коллекции. Используется при работе со списками, таблицами, меню и любыми структурами, где требуется динамическое повторение элементов.

repeat принимает три ключевых аргумента: источник данных, опциональный ключ и шаблон элемента. Упрощённый синтаксис выглядит так:

repeat(x => x.items, html`<div>${x => x}</div>`)

Источник данных может быть массивом или любым объектом, реализующим итерацию. Каждый элемент коллекции передаётся в шаблон как текущий контекст.

Использование ключей для оптимизации

Ключ предназначен для выравнивания элементов данных с DOM-узлами при обновлениях. Это позволяет избежать полного пересоздания всего списка и повышает производительность при сортировках, фильтрациях и обновлениях отдельных элементов.

Пример с ключом:

repeat(
    x => x.items,
    x => x.id,
    html`<item-element item=${x => x}></item-element>`
)

Ключ должен быть стабильным и уникальным для каждого элемента. При отсутствии ключа директива использует индекс массива, что может приводить к ненужным перерисовкам при изменении порядка элементов.

Обновление коллекций

Обновление исходной коллекции вызывает диффинг-алгоритм FAST, который определяет изменения списка и применяет их к DOM. Операции вставки, удаления и перемещения выполняются максимально локально. Такая модель существенно снижает стоимость работы со списками в сравнение с полным повторным рендерингом.

Особенно важно при больших коллекциях: использование ключей и иммутабельных обновлений позволяет минимизировать объём операций.

Поддержка вложенных структур

repeat может использоваться в комбинации с другими директивами и шаблонами, образуя сложные иерархии, например динамические таблицы и деревья:

repeat(
    x => x.rows,
    x => x.id,
    html`
        <tr>
            ${repeat(
                x => x.cells,
                html`<td>${x => x.value}</td>`
            )}
        </tr>
    `
)

Вложенные повторения корректно синхронизируются при изменениях данных как во вложенных коллекциях, так и в верхнем уровне.

Контекст и дата-байндинг

В теле шаблона доступен локальный контекст элемента коллекции и полный контекст компонента. Это позволяет сочетать данные элемента, результаты вычислений и состояние компонента:

repeat(
    x => x.items,
    html`<div class="${(x, c) => c.parent.selected === x ? 'active' : ''}">
        ${x => x.label}
    </div>`
)

Контекст компонента доступен через второй аргумент функции-байндинга и передается неизменным для всех элементов повторения.

Рендеринг компонентов и пользовательских элементов

repeat не ограничивается примитивами. Каждый элемент списка может представлять собой пользовательский Web Component, который получает данные через свойства или атрибуты:

repeat(
    x => x.products,
    x => x.id,
    html`<product-card product=${x => x}></product-card>`
)

FAST обеспечивает корректную инициализацию и обновление свойств пользовательского элемента в процессе диффинга.

Асинхронные источники данных

При работе с асинхронными коллекциями (например fetch-запросами) директива корректно реагирует на обновления после завершения загрузки. Часто используется совместно с реактивными свойствами компонента или сигналами состояния. В результате список появляется сразу после получения данных, а дальнейшие обновления не требуют дополнительных действий.

Взаимодействие с фильтрами и сортировками

repeat не накладывает ограничений на предобработку коллекции. Перед передачей массива в директиву могут применяться сортировки, фильтры или маппинги:

repeat(
    x => x.items.filter(i => i.visible).sort((a, b) => a.order - b.order),
    x => x.id,
    html`<list-item item=${x => x}></list-item>`
)

Важно обеспечивать стабильность ключей после таких операций, иначе потеряется оптимизация перемещений.

Производительность и рекомендуемые практики

Ключевые рекомендации:

  • использовать ключи для больших коллекций или коллекций с динамическим порядком;
  • обновлять коллекции иммутабельно, создавая новый массив при изменениях;
  • избегать тяжёлых вычислений внутри шаблона элемента, выносить их в свойства компонента;
  • использовать пользовательские компоненты для сложной логики, разгружая шаблон.

При соблюдении этих практик repeat обеспечивает плавный рендеринг и масштабируемость интерфейсов.

Сравнение с классическим рендерингом списков

По сравнению с примитивным рендерингом списков через перегенерацию всего DOM-фрагмента при каждом изменении, директива repeat дает:

  • минимизацию вставок и удалений DOM-узлов;
  • перенос существующих элементов при изменении порядка;
  • корректное обновление локального состояния пользовательских элементов;
  • поддержку составных шаблонов и контекста.

Эти свойства делают repeat важным инструментом при создании динамических интерфейсов на базе FAST Element.