Templates
O svelte oferece maneiras de renderizar elementos do DOM de forma dinâmica e condicional.
Por exemplo: Digamos que eu queira exibir um texto apenas quando uma variável for true
.
Podemos fazer isso com o bloco lógico if
.
Mas primeiro vamos entender a sintaxe desses blocos lógicos.
Para abrir um bloco digitamos {#bloco }
e para fechar {/bloco }
. Dentro deles colocamos nossos elementos.
Bloco if
Veja:
<script>
let showText = false
</script>
<!-- Se showText for true, então o elemento p será exibido na tela -->
{#if showText}
<p>Texto</p>
{/if}
<button on:click={() => showText = true}>Mostrar texto</button>
Veja em ação:

Podemos fazer um efeito de “toggle”. Para isso basta fazer o seguinte. showText = !showText
. O que fiz aqui foi fazer a variável showText
receber o valor contrário dela mesma. Se for true
então recebe false
, e vice-versa.

E pra deixar mais legal, vamos mudar o texto também, indicando o que vai acontecer ao clicar no botão.

É possível também utilizar um bloco else
junto com o if
, criando um situação de exclusividade. Ou um ou outro.
<script>
let showText = true
</script>
<!-- Se showText for true, então o elemento p será exibido na tela -->
{#if showText}
<p>O Texto está escondido</p>
<button on:click={() => showText = !showText}>Mostrar texto</button>
{:else}
<p>Agora o Texto aparece</p>
<button on:click={() => showText = !showText}>Esconder texto</button>
{/if}
Veja que o bloco else
tem uma forma de escrever diferente, ele é assim: {:bloco}
.
Faça isso sempre que quiser indicar continuidade em um bloco.

Bloco else if
Podemos fazer várias condições juntas usando else if
. Veja:
<script>
let number = -5;
</script>
{#if number === 0}
<p>{number} é nulo </p>
{:else if number < 0}
<p>{number} é negativo</p>
{:else}
<p>{number} é positivo</p>
{/if}
Perceba que utilizamos {:bloco}
para adicionar mais condições ao bloco {#if}
.
Bloco each
Uma dos recursos mais utizados na programação são os loops. Mas na hora de lidar com elementos Html, a tarefa pode não ser tão simples sem o uso de frameworks. O svelte lida com isso de forma fácil e sem complicações.
Vejamos agora sobre o bloco {#each}
.
Esse bloco é usado sempre que queremos renderizar uma lista de dados, usando um array, ou objetos semelhantes a arrays, ou seja, que possuem uma propriedade length
.
Leia mais em: MDN Mozilla.
Vamos ao código.
<script>
let pentateuch = ['Gênesis', 'Êxodo','Levítico', 'Números', 'Deuteronômio'];
</script>
<ul>
{#each pentateuch as book}
<li>
<a href={`https://www.bibliaon.com/${book}`} target="_blank">{book}</a>
</li>
{/each}
</ul>
pentateuch
é o array.book
é um nome que eu dei para representar cada índice do array. Poderia ser qualquer nome de variável, com exceção das palavras reservadas. Leia mais.
Outra coisa que podemos fazer nesse bloco é pegar o index
do array.
Basta colocar uma vírgula após a variável e definir um nome para o índice. Você escolhe o nome.
<script>
let pentateuch = ['Gênesis', 'Êxodo','Levítico', 'Números', 'Deuteronômio'];
</script>
<ul>
{#each pentateuch as book, i}
<li>
<a href={`https://www.bibliaon.com/${book}`} target="_blank">{book} - {i}</a>
</li>
{/each}
</ul>
No gif a seguir eu resumo um pouco do que disse até agora sobre o bloco each:

Agora vamos usar arrays de objetos.
<script>
let pentateuch = [
{bookName: 'Gênesis', chapters: 50},
{bookName: 'Êxodo', chapters: 40},
{bookName: 'Levítico', chapters: 27},
{bookName: 'Números', chapters: 36},
{bookName: 'Deuteronômio', chapters: 34}
];
</script>
<ul>
{#each pentateuch as book}
<li>
<a href={`https://www.bibliaon.com/${book.bookName}`} target="_blank">{book.bookName}</a>
<span>Chapters: {book.chapters}</span>
</li>
{/each}
</ul>
Simples? Muito! Mas podemos melhorar. Vamos evitar essa sintaxe book.property
e fazer algo melhor. Destructuring.
Veja:
<script>
let pentateuch = [
{bookName: 'Gênesis', chapters: 50},
{bookName: 'Êxodo', chapters: 40},
{bookName: 'Levítico', chapters: 27},
{bookName: 'Números', chapters: 36},
{bookName: 'Deuteronômio', chapters: 34}
];
</script>
<ul>
{#each pentateuch as { bookName, chapters } }
<li>
<a href={`https://www.bibliaon.com/${bookName}`} target="_blank">{bookName}</a>
<span>Chapters: {chapters}</span>
</li>
{/each}
</ul>
É comum alterarmos a lista durante a execução do código, por exemplo, clicando em um botão que remove ou adiciona um item na lista.
Exemplo:
<script>
<script>
let pentateuch = [
{bookName: 'Gênesis', position: 'primeiro'},
{bookName: 'Êxodo', position: 'segundo'},
{bookName: 'Levítico', position: 'terceiro'},
{bookName: 'Números', position: 'quarto'},
{bookName: 'Deuteronômio', position: 'quinto'}
];
function removeFirstBook() {
pentateuch = pentateuch.slice(1)
}
function removeLastBook() {
pentateuch = pentateuch.slice(0, -1)
}
</script>
<button on:click={removeFirstBook}>Remover primeiro livro da lista</button>
<button on:click={removeLastBook}>Remover último livro da lista</button>
<ul>
{#each pentateuch as { bookName, position } }
<li>
<a href={`https://www.bibliaon.com/${bookName}`} target="_blank">{bookName}</a>
<span>é o {position} livro da Bíblia</span>
</li>
{/each}
</ul>

Mas precisamos tomar cuidado com essa manipulação para não cometermos erros que trarão resultados inesperados.
Vamos falar sobre isso agora.
- Primeiro: Tome cuidado na hora de atualizar uma variável. Se tiver dúvida volte na página sobre reatividade.
Eu removi o último item do array pentateuch
usando o método slice
. Mas o método pop
também faz isso, porém ele retorna o elemento removido. Dessa forma, se eu fizer pentateuch = pentateuch.pop()
, a variável vai receber o retorno do método pop
, e não é isso que queremos.
Observe:

Então leia bem sobre métodos de array: Leia mais.
- Segundo: Entenda como o svelte lida com essas listas dinâmicas. Isso é necessário.
Então vamos começar!
O svelte pega uma lista e, usando o bloco each
renderiza os items dela na tela. Mas e se alterarmos essa lista, adicionando, removendo ou mudando a ordem dos items?
Vimos nos exemplos anteriores que funciona normalmente. Mas quero que você entenda como funciona por debaixo dos panos.
Veja essa lista.
- Azul
- Verde
- Amarelo
Quero adicionar a cor “Branco” à lista na última posição, ficando assim:
- Azul
- Verde
- Amarelo
- Branco
O que o svelte faz nesse caso? Bom, ele compara a lista anterior com a nova lista para saber o que deve ser feito. É mais ou menos assim:
Lista atual | Resultado |
---|---|
Azul | Azul |
Verde | Verde |
Amarelo | Amarelo |
Branco |
E a comparação funciona da seguinte forma:
- O item Azul(Lista atual) é igual ao item Azul(Resultado)?
- Sim! Faça nada.
- O item Verde(Lista atual) é igual ao item Verde(Resultado)?
- Sim! Faça nada.
- O item Amarelo(Lista atual) é igual ao item Amarelo(Resultado)?
- Sim! Faça nada.
- O 4º item(Lista atual) é igual ao item Branco(Resultado)?
- Não! Ele não existe. Então adicione à lista.
Entendeu até aqui? Então segura que vem mais. Preste atenção agora!
E se eu adicionar o item “Branco” à lista em uma posição diferente, por exemplo, na segunda posição?
Vejamos:
Lista atual | Resultado |
---|---|
Azul | Azul |
Verde | Branco |
Amarelo | Verde |
Amarelo |
A comparação fica assim:
- O item Azul(Lista atual) é igual ao item Azul(Resultado)?
- Sim! Faça nada.
- O item Verde(Lista atual) é igual ao item Branco(Resultado)?
- Não! Então atualize a “Lista atual”. O item “Verde” vira “Branco”.
Nesse momento a “Lista atual” está assim:
Azul
Branco
O item Amarelo(Lista atual) é igual ao item Verde(Resultado)?
- Não! Então atualize a “Lista atual”. O item “Amarelo” vira “Verde”.
Nesse momento a “Lista atual” está assim:
Azul
Branco
Verde
O 4º item(Lista atual) é igual ao item Amarelo(Resultado)?
- Não! Ele não existe. Então adicione à lista.
No final a “Lista atual” ficará assim, atingindo o resultado final.
- Azul
- Branco
- Verde
- Amarelo
Percebeu? O svelte atualiza os valores dos itens ao invés de trocá-los de posição. Ele faz um comparação simples do texto do item, atualiza o que for diferente, adiciona o que faltar e remove o que sobrar. Viu como é necessário entender os fundamentos do framework? Um dasavisado por ter problemas de performance ao tentar atualizar uma lista enorme.
Mas por quê? Ora, do segundo item pra baixo, todos foram atualizados. Imagina isso com vários itens? Nada bom.
Um outro problema que pode acontecer é quando usamos o bloco each
em componentes. Se o componente tiver uma propriedade fixa na hora da inicialização, quando você atualizar a lista, essa propriedade não vai mudar, e isso vai gerar uns bugs.
Vamos ver isso na prática.
Primeiro eu crio o componente “Color.svelte”
<!-- Color.svelte -->
<script>
// Essa variável está sendo exportada, portanto ela será atualizada quando for solicitado.
export let color;
// Essas constantes não. Estão fixas e seus valores são definidos na inicialização do componente.
// Ou seja, quando ele nesce.
const listNames = {'blue': 'Azul', 'yellow': 'Amarelo', 'green': 'Verde'}
const colorName = listNames[color]
</script>
<p style="color: {color}; font-weight: bold">Essa cor é: {colorName}</p>
Aqui eu importo o componente “Color.svelte”, faço um loop usando a lista colors
, e crio uma função para remover o primeiro item da lista.
<!-- App.svelte -->
<script>
import Color from './Color.svelte'
let colors = ['blue', 'yellow', 'green']
function removeFirstColor() {
colors = colors.slice(1)
}
</script>
<button on:click={removeFirstColor}>Remover primeira cor</button>
{#each colors as color}
<Color {color} />
{/each}
Agora veja o que acontece quando eu clico no botão.

A cor da letra muda, mas o texto não. Sempre fica escrito “Azul”. Isso é um problema! mas…
Mas não para por aqui. Apresento à vocês o bloco each
com chave, que resolve isso.
Bloco each com chave
O bloco each
com chave cria um identificador único para cada elemento dentro do bloco e com isso o svelte saberá qual deve ser alterado quando a lista for atualizada.
E para fazer isso não poderia ser mais simples.
<!-- Veja que apenas definimos entre parênteses a (chave). Não precisa escrever código no elemento -->
{#each colors as color (color)}
<Color {color} />
{/each}
Basta definir entre parênteses um valor para servir como chave. Leia abaixo o que diz o site oficial.
Você pode usar qualquer objeto como chave, como Svelte usa Map internamente… Documentação
Usar uma string ou número geralmente é mais seguro, pois significa que a identidade persiste sem igualdade referencial, por exemplo, ao atualizar com dados novos de um servidor API.
Leia sobre o Map.
Muito simples. Agora veja como tudo funciona como gostaríamos.

E quando vou saber qual utilizar? Uma regra básica.
- Quer apenas exibir uma lista de itens na tela? Use
each
sem chave. - Quer interagir com a lista? Use
each
com chave.
Bloco await
Esse é, sem dúvidas, o bloco mais interessante que o svelte oferece. Pelo nome você já sabe que é para trabalhar com promises.
Segue abaixo nosso código de exemplo.
<script>
async function getFoxImg() {
const response = await fetch('https://randomfox.ca/floof/');
const json = await response.json();
return json;
}
let fox = getFoxImg()
function showFoxImg() {
fox = getFoxImg()
}
</script>
<button on:click={showFoxImg}>Buscar imagem aleatória</button>
{#await fox}
<p>Carregando...</p>
{:then data}
<div>
<img src={data.image} alt="dog" />
</div>
{/await}
<style>
div {
width: 200px
}
div img {
max-width: 100%
}
</style>
Executando isso, temos:

Basicamente o que estamos fazendo é buscar uma imagem aleatória e exibindo na tela. Quero que volte suas atenções ao bloco {#await fox}
.
A variável fox pode ser qualquer expressão javascript válida, mas que retorne uma promise. E é isso que fazemos nesse trecho aqui:
let fox = getFoxImg()
.
A função getFoxImg
é assíncrona, e toda função assíncrona retorna uma promise. Agora vamos entender o funcionamento do bloco await
.
Bom, esse bloco tem algumas opções. Vejamos:
{#await expression}...{:then name}...{:catch name}...{/await}
{#await expression}...{:then name}...{/await}
{#await expression then name}...{/await}
{#await expression catch name}...{/await}
Vamos detalhar.
{#await expression}...{:then name}...{:catch name}...{/await}
Essa é a forma mais completa, reunindo todos os estados de uma promise. “Pending”, “Fulfilled” e “Rejected”.
No nosso exemplo, não usei essa forma pois nesse caso não quero exibir nada caso a promise seja rejeitada. Mas vamos simular uma rejeição da promise e ver o que acontece. Vou apenas alterar a função getFoxImg()
.
<script>
async function getFoxImg() {
const response = await fetch('https://randomfox.ca/floof/');
// Vou forçar a rejeição dessa promise. Não faz sentido, é só para testar o catch.
if(response.ok) {
throw new Error('Não foi possível buscar a imagem');
}
}
</script>
Agora vou alterar o bloco await
adicionando um “catch” para exibir o erro na tela.
{#await fox}
<p>Carregando...</p>
{:then data}
<div>
<img src={data.image} alt="fox" />
</div>
{:catch error}
<p>{error.message}</p>
{/await}

{#await expression}...{:then name}...{/await}
Essa variação foi a que usamos no primeiro exemplo, sem o “catch”, ou seja, sem o estado “Rejected”.
{#await expression then name}...{/await}
Essa variação mais curta não usa o estado “Pending”, ou seja, use quando não quiser exibir um loading na tela.

{#await expression catch name}...{/await}
E essa última variação é quando você apenas quer usar o estado “Rejected”, ou seja, apenas exibir o erro.
