Utilitário de repetição
O utilitário repeat é a forma recomendada pelo Markup para renderizar dados iteráveis ou conteúdo repetido. Ele lida com coisas como cache e rastreamento do modelo, garantindo que as alterações na lista aconteçam apenas nos itens que precisam delas.
html`${repeat(todos, renderTodo)}`Por que usar repetir?
Os modelos Markup já lidam com arrays, mas como qualquer outro valor injetado, o Markup rastreia tudo e não seus itens individuais.
const [todos, updateTodos] = state([])
html`${() => todos().map(renderTodo)}`.render(document.body)
updateTodos((prev) => [
...prev,
{
name: 'Go to gym',
status: 'pending',
},
])O código acima funcionará perfeitamente no que diz respeito à renderização de uma lista. O problema fica evidente quando um único item é alterado, adicionado ou removido. Isso ocorre porque a função será chamada novamente, gerando uma nova lista de conteúdo para renderizar. Se Markup vir uma nova lista, ele renderizará tudo novamente.
A melhor maneira é não mapear dinamicamente a lista na renderização, mas na criação, para que o Markup sempre tenha as coisas que deseja renderizar para que possa verificar se é diferente de antes ou não.
const [todos, updateTodos] = state([])
html`${todos}`.render(document.body)
updateTodos((prev) => [
...prev,
renderTodo({
name: 'Go to gym',
status: 'pending',
}),
])Isso é exatamente o que o utilitário repeat faz por você, apenas pegando os dados e a função de renderização.
Números
O auxiliar repeat aceita um número entre muitas coisas. Este número representa o número de vezes que você deseja que a função de renderização de retorno de chamada precise ser chamada.
html`${repeat(3, html`<spa></span>`)}`A função de retorno de chamada será chamada com números de 1 até o número que você forneceu junto com os índices.
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>Iteráveis e literais de objeto
Além disso, repeat pode consumir qualquer Object literal ou objeto iterável e isso inclui:
- Matriz
- Definir
- Mapa
- Corda
- qualquer objeto com Symbol.iterator
const iterable = {}
iterable[Symbol.iterator] = function* () {
yield 1
yield 2
yield 3
}
html`${repeat(iterable, renderItem)}`Como o modelo Markup não processa a renderização de tais objetos (exceto Array), esta é uma vantagem adicional no uso de repeat. Você não precisa se preocupar em converter nenhum dado em Array apenas para poder iterar e renderizar.
A função de retorno de chamada sempre será chamada com as entradas e o índice.
const employeesSalary = {
'john doe': 30000,
'jane doe': 54000,
}
html`${repeat(employeesSalary, ([name, salary], index) => html`...`)}`Estado vazio
O repeat também consome um terceiro argumento opcional que é uma função que será chamada para retornar o que renderizar quando os dados estiverem vazios.
html`${repeat(todos, renderTodo, () => html`<p>No todos yet!</p>`)}`Chaves e opções
Por padrão, repeat usa os próprios itens da lista como chaves de identidade para rastrear atualizações. Se seus itens são objetos ou você deseja rastreá-los por um identificador exclusivo, você pode passar um objeto de opções como terceiro argumento:
const options = {
key: (todo, index) => todo.id,
empty: () => html`<p>No todos yet!</p>`,
}
html`${repeat(todos, renderTodo, options)}`O objeto de opções oferece suporte às seguintes propriedades:
key(função): Uma função seletora que retorna uma chave exclusiva para cada item. Altamente recomendado para listas dinâmicas onde os itens podem ser reordenados, adicionados ou removidos.empty(função): Uma função que retorna o modelo ou nó para renderizar quando a coleção está vazia.
Renderização de lista preguiçosa
Para otimizar listas com um grande número de itens complexos, você pode combinar o utilitário repeat com o utilitário visible. Isso adia a renderização dos itens da lista fora da tela até que eles estejam prestes a serem exibidos:
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>
`