Répéter l'utilitaire

L'utilitaire repeat est le moyen recommandé par Markup pour restituer des données itérables ou du contenu répétitif. Il gère des éléments tels que la mise en cache et le suivi du modèle, garantissant que les modifications de la liste ne concernent que les éléments qui en ont besoin.

javascript
html`${repeat(todos, renderTodo)}`

Pourquoi utiliser la répétition ?

Les modèles Markup gèrent déjà les tableaux, mais comme toute autre valeur injectée, Markup suit l'ensemble et non ses éléments individuels.

javascript
const [todos, updateTodos] = state([])

html`${() => todos().map(renderTodo)}`.render(document.body)

updateTodos((prev) => [
    ...prev,
    {
        name: 'Go to gym',
        status: 'pending',
    },
])

Le code ci-dessus fonctionnera très bien pour le rendu d'une liste. Le problème devient évident lorsqu'un seul élément change, est ajouté ou supprimé. En effet, la fonction sera à nouveau appelée, générant une toute nouvelle liste de contenu à restituer. Si Markup voit une nouvelle liste, il restituera tout.

La meilleure façon est de ne pas mapper dynamiquement la liste lors du rendu mais lors de la création afin que Markup ait toujours les éléments que vous souhaitez restituer afin qu'il puisse vérifier si c'est différent d'avant ou non.

javascript
const [todos, updateTodos] = state([])

html`${todos}`.render(document.body)

updateTodos((prev) => [
    ...prev,
    renderTodo({
        name: 'Go to gym',
        status: 'pending',
    }),
])

C'est exactement ce que l'utilitaire repeat fait pour vous en prenant simplement les données et la fonction de rendu.

Numéros

L'assistant repeat accepte un certain nombre de choses parmi tant d'autres. Ce nombre représente le nombre de fois que vous souhaitez que la fonction de rendu de rappel soit appelée.

javascript
html`${repeat(3, html`<spa></span>`)}`

La fonction de rappel sera appelée avec des nombres allant de 1 au numéro que vous avez fourni avec les index.

javascript
html`${repeat(3, (n, index) => html`<spa>${n} - ${index}</span>`)}`.render(
    document.body
)
// <span>1 - 0</span><span>2 - 1</span><span>3 - 2</span>

Itérables et littéraux d'objet

De plus, repeat peut consommer n'importe quel objet littéral ou objet itérable, ce qui inclut :

javascript
const iterable = {}

iterable[Symbol.iterator] = function* () {
    yield 1
    yield 2
    yield 3
}

html`${repeat(iterable, renderItem)}`

Étant donné que le modèle Markup ne gère pas le rendu de tels objets (à l'exception du tableau), il s'agit d'un avantage supplémentaire dans l'utilisation de repeat. Vous n'avez pas à vous soucier de la conversion de données en tableau uniquement pour pouvoir itérer et restituer.

La fonction de rappel sera toujours appelée avec les entrées et l'index.

javascript
const employeesSalary = {
    'john doe': 30000,
    'jane doe': 54000,
}

html`${repeat(employeesSalary, ([name, salary], index) => html`...`)}`

État vide

Le repeat consomme également un troisième argument facultatif qui est une fonction qui sera appelée pour renvoyer ce qu'il faut restituer lorsque les données sont vides.

javascript
html`${repeat(todos, renderTodo, () => html`<p>No todos yet!</p>`)}`

Clés et options

Par défaut, repeat utilise les éléments de la liste eux-mêmes comme clés d'identité pour suivre les mises à jour. Si vos éléments sont des objets ou si vous souhaitez les suivre grâce à un identifiant unique, vous pouvez plutôt passer un objet options comme troisième argument :

javascript
const options = {
    key: (todo, index) => todo.id,
    empty: () => html`<p>No todos yet!</p>`,
}

html`${repeat(todos, renderTodo, options)}`

L'objet options prend en charge les propriétés suivantes :

Rendu de liste paresseux

Pour optimiser les listes comportant un grand nombre d'éléments complexes, vous pouvez combiner l'utilitaire repeat avec l'utilitaire visible. Cela diffère le rendu des éléments de liste hors écran jusqu'à ce qu'ils soient sur le point de défiler :

javascript
import { html, repeat, visible } from '@beforesemicolon/markup'

html`
    <ul>
        ${repeat(
            todos,
            (todo, index) =>
                visible(
                    () => html`<todo-item item="${todo}"></todo-item>`,
                    html`<li class="placeholder">Loading...</li>`,
                    { eager: index < 10 } // render first 10 immediately
                ),
            { key: (todo) => todo.id }
        )}
    </ul>
`
modifier ce document