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.
Leave a Reply