Skip to main content

Every component has a lifecycle that starts when it is created, and ends when it is destroyed. There are a handful of functions that allow you to run code at key moments during that lifecycle. The one you'll use most frequently is onMount, which runs after the component is first rendered to the DOM.

In this exercise, we have a <canvas> that we'd like to animate, using the paint function in gradient.js. Begin by importing the onMount function from svelte:

App.svelte
<script>
	import { onMount } from 'svelte';
	import { paint } from './gradient.js';
</script>

Then, add a callback that runs when the component mounts:

App.svelte
<script>
	import { onMount } from 'svelte';
	import { paint } from './gradient.js';

	onMount(() => {
		const canvas = document.querySelector('canvas');
		const context = canvas.getContext('2d');

		requestAnimationFrame(function loop(t) {
			requestAnimationFrame(loop);
			paint(context, t);
		});
	});
</script>

In a later exercise, we'll learn how to get an element reference without using document.querySelector.

So far so good — you should see gently undulating colours in the shape of the Svelte logo. But there's one problem — the loop will continue even after the component has been destroyed. To fix that, we need to return a cleanup function from onMount:

App.svelte
onMount(() => {
	const canvas = document.querySelector('canvas');
	const context = canvas.getContext('2d');

	let frame = requestAnimationFrame(function loop(t) {
		frame = requestAnimationFrame(loop);
		paint(context, t);
	});

	return () => {
		cancelAnimationFrame(frame);
	};
});

Next: beforeUpdate and afterUpdate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script>
	import { paint } from './gradient.js';
</script>
 
<canvas
	width={32}
	height={32}
/>
 
<style>
	canvas {
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		background-color: #666;
		mask: url(./svelte-logo-mask.svg) 50% 50% no-repeat;
		mask-size: 60vmin;
		-webkit-mask: url(./svelte-logo-mask.svg) 50% 50% no-repeat;
		-webkit-mask-size: 60vmin;
	}
</style>
 
initialising