Ciclo de vida
Veremos nessa página um importante assunto sobre os componentes svelte: Ciclo de vida.
Veja o que diz a documentação:
Cada componente tem um ciclo de vida que começa quando é criado e termina quando é destruído. Há um punhado de funções que permitem executar o código em momentos-chave durante esse ciclo de vida. Documentação
Vamos começar pelo mais utilizado, o onMount
.
On Mount
Essa função é executada depois que o componente é renderizado pela primeira vez. Sua sintaxe é onMount(callback)
.
<script>
import { onMount } from 'svelte';
onMount(() => {
console.log('Componente montado.');
});
</script>
Podemos retornar uma função de onMount
que será executada quando o componente for destruído. Isso é útil, por exemplo, quando trabalhamos com setTimeout
e setInterval
. Se não removermos o timer criado quando o componente for destruído, isso poderá causar vazamento de memória. Leia mais.
Observe abaixo:

No exemplo acima eu demonstrei um problema que acontece muito quando utilizamos setInterval
. Quando o componente foi desmontado sem utilizar clearInterval
, houve um acúmulo de timers resultando em um console.log
acelerado.
Usando clearInterval
isso não acontece.
Podemos fazer chamadas assíncronas utilizando o onMount
.
<script>
import { onMount } from 'svelte';
let data = {};
onMount(async () => {
const response = await fetch('https://random-data-api.com/api/v2/users');
const json = await response.json();
data = json;
})
</script>
{#if data}
<h1>{data.first_name}</h1>
<img src={data.avatar} alt="" />
{:else}
<p>Carregando...</p>
{/if}
<style>
img {
width: 100px;
max-width: 100%
}
</style>
Mas veja que toda função assíncrona no javascript retorna uma promise. Então, nesse caso, não podemos utilizar o retorno da função onMount
.
Isso aqui não vai funcionar!
<script>
import { onMount } from 'svelte';
onMount(async () => {
setInterval(() => {
console.log('beep')
}, 1000)
// Esse console.log nunca será executado.
// Dessa forma, qualquer coisa executada aqui não vai funcionar.
return () => console.log('Componente desmontado')
});
</script>

Fique atento!
On Destroy
Embora não seja possível executar uma função quando o componente for desmontado em um onMount
assíncrono, podemos fazer isso com uma função de ciclo de vida específico. O onDestroy
.
Voltando ao exemplo anterior, vamos corrigir o problema.
<script>
import { onMount, onDestroy } from 'svelte';
// Declaro a variável fora do "onMount" pra pegar a referência do "setInterval"
// e utilizar no "clearInterval".
let interval;
onMount(async () => {
interval = setInterval(() => {
console.log('beep')
}, 1000)
// Embora isso não funcione...
// return () => console.log('Componente desmontado')
});
// Isso aqui sim.
onDestroy(() => {
clearInterval(interval)
console.log('Componente desmontado')
})
</script>
Problema resolvido!
Você pode executar uma função quando o componente for desmontado de 2 maneiras.
- Com o retorno de
onMount
, caso não seja assíncrono. - Com a função
onDestroy
.
Before Update
A função beforeUpdate
é executada imediatamente antes do componente ser atualizado e, na primeira execução, será antes de onMount
.
<script>
import { onMount, beforeUpdate } from 'svelte';
onMount(() => console.log('Segundo'))
beforeUpdate(() => console.log('Primeiro'))
</script>
O resultado desse script
será:
- “Primeiro”
- “Segundo”
Vamos ver um outro exemplo.
<script>
import { onMount, beforeUpdate } from 'svelte';
let count = 0;
onMount(() => console.log('On Mount', count))
beforeUpdate(() => {
console.log('Before update', count)
})
function handleClick() {
count += 10;
}
</script>
<button on:click={handleClick}>Add + 10</button>
<h2>{count}</h2>

No exemplo acima demonstro que o beforeUpdate
é acionado antes de onMount
e também antes de cada atualização de estado. Mas e se eu atualizar o estado dentro de beforeUpdate
, o que acontecerá?
Bom, vamos pensar um pouco! Siga o raciocínio.
- O componente vai ser montado na tela
beforeUpdate
é executado pela primera vez antes deonMount
count
é atualizadobeforeUpdate
é executado novamentecount
é atualizadobeforeUpdate
é executado novamente- …
- …
- …
- loop infinito
Isso aconte pois toda vez que um estado é colocado para atualizar, beforeUpdate
agenda uma função para ser executada antes. Mas como a atualização de estado está dentro dessa função, entra em loop infinito.
Ou melhor, entraria… Mas o svelte é inteligente nesse ponto. Para evitar um loop infinito, ele executa a função de beforeUpdate
apenas mais um vez.

No entanto, esse cuidado somos nós que temos que ter. Somos programadores e a máquina executa as instruções que escrevemos.
Se você fizer isso:
<script>
while (true) {
console.log(100000 ** 400000);
}
</script>
Não adianta reclamar se sua máquina travar.
After Update
Ao contrário de beforeUpdate
, o afterUpdate
é executado na primeira vez após onMount
e também após cada atualização de estado.
<script>
import { afterUpdate } from 'svelte';
afterUpdate(() => {
console.log('Componente atualizado');
});
</script>
As observações a respeito do beforeUpdate
são as mesmas para o afterUpdate
.
Tick
No svelte as alterações no DOM não são feitas imediatamente. Quando há alguma alteração de estado, ele aguarda pra ver se há mais alterações a serem feitas, inclusive em outros componentes. Por esse motivo pode acontecer algum resultado inesperado caso você nã isso.
Veja o exemplo abaixo:
<script>
let count = 1;
$: double = count * 2;
function handleClick() {
count++
// Aqui "double" ainda não foi atualizado e mostrará o valor antigo.
console.log(double)
}
</script>
<button on:click={handleClick}>+</button>
<h1>{count} - {double}</h1>
Um outro exemplo é quando tentamos acessar as propriedades de algum elemento do DOM logo após uma alteração de estado desse elemento.
<script>
import { tick } from 'svelte';
let text = '';
let h2;
async function handleInput(e) {
text = e.target.value;
// O texto de h2 ainda não foi atualizado. "console.log" exibirá o valor antigo
// Descomente a linha abaixo.
// await tick()
// Agora o "console.log" vai exibir o valor correto
console.log(h2.innerText)
}
</script>
<label for="classe">Nome da classe</label>
<input id="classe" type="text" on:input={handleInput} />
<h2 bind:this={h2}>{text}</h2>

Veja o que diz a documentação.
tick
retorna uma promessa que resolve assim que quaisquer alterações de estado pendentes forem aplicadas ao DOM (ou imediatamente, se não houver alterações de estado pendentes). Documentação
Por retornar uma promise, devemos colocar um async
na declaração da função:
<script>
async function handleInput(e) {
...
await tick()
}
</script>
ou fazer assim:
<script>
function handleInput(e) {
...
tick().then(() => {})
}
</script>