Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
Svelte is an up and coming front end framework for developing front end web apps.
It’s simple to use and lets us create results fast.
In this article, we’ll look at the lifecycle hooks of a Svelte component.
Component Lifecycle
Every Svelte component has a lifecycle. It starts when it’ created and ends when it’s destroyed.
There’re a handful of functions that allows us to run code at key moments of the lifecycle.
The most frequently used is onMount
. It’s run after the component is first rendered to the DOM.
We can add a onMount
handler to our component as follows:
<script>
import { onMount } from "svelte";
let joke = { value: { joke: "" } };
onMount(async () => {
const res = await fetch(`https://api.icndb.com/jokes/20`);
joke = await res.json();
});
</script>
<p>{joke.value.joke}</p>
The code above calls the Chuck Norris API to get a joke when the component loads.
Then we display it after it’s loaded.
onDestroy
onDestroy
‘s callback is called when the when the component is being destroyed.
Cleanup code and anything else that runs when the component can go into onDestroy
‘s callback.
For instance, we can write:
<script>
import { onDestroy } from "svelte";
let seconds = 0;
const interval = setInterval(() => seconds++, 1000);
onDestroy(() => clearInterval(interval));
</script>
<p>Seconds: {seconds}</p>
In the code above, we call setInterval
, which returns an interval ID object which we set as the value of interval
.
Then when the component is being destroyed, we call clearInterval
to clear the interval object from memory by passing interval
into clearInterval
in the onDestroy
callback.
beforeUpdate and afterUpdate
beforeUpdate
runs immediately before the DOM has been updated.
afterUpdate
is used for running code once the DOM is in sync with our data.
For instance, if we want to scroll to the bottom of the div if the div overflows the window height, we can write the following code:
<script>
import { beforeUpdate, afterUpdate } from "svelte";
let div;
let autoscroll;
let arr = [];
setTimeout(() => {
arr = new Array(100).fill("foo");
}, 100);
beforeUpdate(() => {
autoscroll = div && div.offsetHeight + div.scrollTop > div.scrollHeight - 20;
});
afterUpdate(() => {
if (autoscroll) {
window.scrollTo(0, div.scrollHeight);
}
});
</script>
<div bind:this={div}>
{#each arr as a}
<p>{a}</p>
{/each}
</div>
The code:
div && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
checks if the height of the div is bigger than the scroll height, which includes the height that’s not visible on the screen.
Then in the afterUpdate
callback, we can scroll to the bottom of the div if there’s overflow as returned by the boolean above.
Tick
tick
is a function that returns a promise that resolves as soon as any pending state changes have been applied to the DOM.
When the component state is invalidated in Svelte, it doesn’t update the DOM immediately. It waits until the next microtask to see if there’re any changes that need to be applied.
This allows the batching of updates.
When we select a range of text in the text area and hit the tab key to toggle its case, then the current selection is cleared and the cursor jumps to the end.
We can retain the selection after the tab key is pressed by in a Textarea by writing the following code:
<script>
import { tick } from "svelte";
let text = "";
async function handleKeydown(event) {
if (event.which !== 9) return;
event.preventDefault();
const { selectionStart, selectionEnd, value } = this;
const selection = value.slice(selectionStart, selectionEnd);
const replacement = /[a-z]/.test(selection)
? selection.toUpperCase()
: selection.toLowerCase();
text =
value.slice(0, selectionStart) + replacement + value.slice(selectionEnd);
await tick();
this.selectionStart = selectionStart;
this.selectionEnd = selectionEnd;
}
</script>
<textarea bind:value={text} on:keydown={handleKeydown}></textarea>
In the code above we have the handleKeydown
to see if the tab key is pressed.
We keep the text from changing by setting the text
to the same content as before.
If it is, then we set the selectionStart
and selectionEnd
after tick
is called to retain the selection.
Conclusion
We can use the lifecycle methods to run the code we want during a stage of the lifecycle.
There’s one for when the component loaded, one for when a component is destroyed, 2 for DOM updates, and one for when the component’s state is updated.