Svelte.js 3 Lifecycle Hooks Tutorial

In this tutorial we learn how to tap into Svelte's lifecycle process with special functions.

We also cover the mounting and unmounting phase, the update phase and how to force specific updates in a batch with tick.

Lesson Project

If you want to follow along with the examples in this lesson, you’ll need a Svelte app that was cloned with degit or scaffolded with Vite

If you already have an app from previous lessons, you can use that instead.

The Svelte Instance Lifecycle

Svelte has an elaborate lifecycle and follows certain steps to render an application. We can execute our own code during some of these steps by hooking into this lifecycle process.

Svelte’s lifecycle can be broken down into 4 phases.

  1. Creation (Mounting)
  2. Updating
  3. Ticking
  4. Destruction (Unmounting)

All of these phases have special functions that allow us to execute our own code.

The functions (or hooks) are imported from the ‘svelte’ package, and takes a callback as an argument. The callback can also be asynchronous if we need, like with an HTTP request.

Syntax: lifecycle function callback
hookName(() => {
  // logic
})

Let’s go through the lifecycle and the order in which the hooks are invoked.

The Creation & Destruction lifecycles in Svelte

A component’s lifecycle starts when it’s created (mounted) and ends when it’s destroyed (unmounted).

Svelte provides us with 2 lifecycle hooks in this phase.

  • onMount
  • onDestroy

1. Mounting phase: 'onMount'

The onMount function schedules its callback to run as soon as the component has been mounted to the DOM.

This is the perfect place to perform HTTP requests, DOM manipulations or set up event listeners.

As an example, let’s create a variable and log its value to the console. Then we’ll use the onMount function to change the value and log it to the console again.

Example: src/App.svelte
<script>
  import { onMount } from 'svelte'

  // before mount
  let msg = 'Hello'
  console.log(msg)

  // mounted
  onMount(() => {
    msg = 'Hello there'
    console.log(msg)
  })
</script>

If we save and take a look at the Console tab in the browser’s developer tools, we’ll see the defined message first and then the one we changed in onMount .

Output:
Hello
Hello there

Let’s add another console log after the onMount function changes the message.

Example: src/App.svelte
<script>
  import { onMount } from 'svelte'

  // before mount
  let msg = 'Hello'
  console.log(msg)

  // mounted
  onMount(() => {
    msg = 'Hello there'
    console.log(msg)
  })

  // before mount
  console.log(msg)
</script>

This time, we see the unchanged message twice.

Before the mounting phase, Svelte is just aware of everything in the script block. It hasn’t compiled the template yet.

Once the component is mounted, Svelte will run the lifecycle hook and then compile the template. For example, all the string interpolations are replaced with the concrete values that should be shown to the user.

To demonstrate, let’s output the message in a paragraph.

Example: src/App.svelte
<script>
  import { onMount } from 'svelte'

  // before mount
  let msg = 'Hello'
  console.log(msg)

  // mounted
  onMount(() => {
    msg = 'Hello there'
    console.log(msg)
  })

  // before mount
  console.log(msg)
</script>

<p>{msg}</p>

If we run the example in the browser, we’ll see the updated message on the page.

2. Unmounting phase: 'onDestroy'

The onDestroy function schedules its callback to run before the component is unmounted (before we stop seeing the component in the browser).

At this point the component is still fully functional so we can perform any necessary cleanup like cancelling network requests or removing event listeners.

The Updating lifecycle in Svelte

The update phase starts when something inside the component changes and ends when the DOM has been updated with that change.

Svelte provides us with 2 lifecycle hooks in this phase.

  • beforeUpdate
  • afterUpdate

1. Before the Update phase: 'beforeUpdate'

The beforeUpdate hook runs after the component receives an updated state, but before the DOM is updated with that state.

As an example, let’s create two buttons that increment or decrement a counter. Then we’ll use the beforeUpdate method to log a message to the console.

Example: src/App.svelte
<script>
  import { beforeUpdate } from 'svelte'

  let counter = 0

  beforeUpdate(() => {
    console.log('Log before counter value updates')
  })
</script>

<p>{ counter }</p>
<button on:click={() => counter++}>Increment</button>
<button on:click={() => counter--}>Decrement</button>

If we run the example in the browser and click on the buttons, the console logs the message before the number changes.

But you may have noticed that the console logged the message before you even clicked on one of the buttons. That’s because the first call to beforeUpdate happens even before the component is mounted.

We should keep this in mind and be careful when trying to access any DOM elements in this hook.

2. After the Update phase: 'afterUpdate'

The afterUpdate hook runs after the DOM has been updated with the new component state (when we see the update on the page).

note The template doesn’t unmount when the user changes data. It’s only a rerender, so there is no mounting or unmounting phase.

Ticking cycle

This isn’t really a phase, nor is its function actually a lifecycle hook. But it’s so closely related to the lifecycle that it’s commonly grouped with the lifecycle hooks.

The tick function returns a promise that will be resolved when the update phase is finished. That’s to say, when any pending state changes have been applied to the DOM.

Changes in a component aren’t updated immediately, Svelte tries to batch it with any other changes from other components to avoid unnecessary work in the browser.

We can use tick to force a specific update in that batch.

To demonstrate, let’s create a button that changes a greeting message and log that to the console with a reactive statement . The function that updates the greeting message will make two updates that Svelte will batch and only apply the second update.

Example: src/App.svelte
<script>
  let greeting = 'World'

  function updateGreeting() {
    greeting = 'there'
    greeting = 'John'
  }

  $: console.log(greeting)
</script>

<button on:click={updateGreeting}>Update greeting</button>

If we run the example in the browser and click the button, it will change the greeting message to the second update in the function.

Output:
World
John

Now let’s say we need the first update to be applied, for whatever reason. We can use the tick function right below it to force Svelte to apply the update.

note Remember that tick returns a promise that we need to await , so we have to mark the function where it’s used with async .

Example: src/App.svelte
<script>
  import { tick } from 'svelte'

  let greeting = 'World'

  async function updateGreeting() {
    greeting = 'there'
    // force the "there" update
    // before the "John" update
    await tick()

    greeting = 'John'
  }

  $: console.log(greeting)
</script>

<button on:click={updateGreeting}>Update greeting</button>

If we run the example and click on the button, it will log the first update before the second.

Output:
World
there
John