Reactivity

Reactivity is Svelte’s superpower. If you’re unfamiliar reactivity is how you keep your DOM in sync with your application state.

When you’re developing an application you want a change in your application state like adding a song to a playlist be reflected immediately in the DOM and re-render what changed.

You would have to write all this boilerplate code to update the user interface before you even start developing your application and that’s what JavaScript frameworks like Svelte do for us so you don’t have to think about it.

Svelte’s reactivity is based on assignments. To change state and trigger a re-render you assign a value to a variable you declared and it’s going to update. We have already done this.

App.svelteCopy

<script>
	let count = 0

	function increment() {
	  count = count + 1
	}
</script>

Because we need to assign a value for Svelte to pick it up methods like push won’t trigger an update until we reassign it. We can avoid doing the extra step by using the JavaScript spread operator ... to keep existing items and add the new item.

App.svelteCopy

<script>
  let list = ['React', 'Vue']

  function handleClick() {
    // doesn't update
    list.push('Svelte')
    // until you assign it
    list = list
    // so it's easier doing this
    list = [...list, 'Svelte']
  }
</script>

<p>{list}</p>
<button on:click={handleClick}>Click</button>

Sometimes you need to change a value based on other values. This is referred to as a computed property.

Svelte has reactive declarations using the $: syntax which is valid JavaScript label syntax that Svelte stole for itself.

Using the $: syntax is saying “re-run this code whenever any of the referenced values change”.

App.svelteCopy

<script>
	// state
	let items = [1, 2, 3, 4]

	// computed
	$: amount = items.length

	function addItem() {
		items = [...items, items.length + 1]
	}
</script>

<p>The amount is {amount}</p>
<button on:click={addItem}>Add item</button>

Think about it as giving Svelte dependencies to watch and rerun the code when the value changes because in $: albumLength = getAlbumLength(album) on the right album is the referenced value.

App.svelteCopy

<script>
	// state
	let album = [
		{ track: 'Track 1', length: 180 },
		{ track: 'Track 2', length: 240 },
		{ track: 'Track 3', length: 280 },
	]

	// computed
	$: albumLength = getAlbumLength(album)

	function getAlbumLength(album) {
		let lengthSeconds = album.reduce(
			(totalLength, currentValue) => {
			return totalLength + currentValue.length
		}, 0)

		let [minutes, seconds] =
		(lengthSeconds / 60)
		.toFixed(2)
		.toString()
		.split('.')

		return { minutes, seconds }
	}

	function addTrack() {
		album = [...album, { track: 'Track 4', length: 420 }]
	}
</script>

<p>
	Album length is {albumLength.minutes} minutes and
	{albumLength.seconds} seconds.
</p>
<button on:click={addTrack}>Add track</button>

One of the cool things you can do is log a value whenever it changes so it’s easy to see what’s going on.

App.svelteCopy

<script>
	let count = 0
	$: console.log(count)
</script>

<button on:click={() => count += 1}>Click</button>

You can have reactive blocks.

App.svelteCopy

<script>
	let count = 0

	$: {
		console.log(`The count is ${count}`)

		if (count >= 4) {
			console.log('Restarting count.')
			count = 0
		}
	}
</script>

<button on:click={() => count += 1}>Click</button>

Ignore the weird syntax highlighting because there isn’t an extension for .svelte files so it’s treated like .html which can be fixed by using quotes on:click="{() => count += 1}". Your editor is going to support the syntax if you use the Svelte for VS Code extension.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *