So, we all saw the presentation by Rich Harris, the creator of the Svelte Javascript compiler, and are excited about implementing spreadsheet reactivity in our projects. However, even though the concept is easy to grasp when looking at simple examples implementing reactivity is sometimes not obvious when working with real data.
In the last months, I have worked hard on Wisvids an online math video subscription service build with Svelte JS and this article explores some examples of the reactive patterns used.
Basic reactivity rules
Basically, you will get the main bulk of reactivity for free without writing extra code in Svelte. Any statement with a = operator will cause the variable to updated automatically in the HTML.
You will quickly find out that when updating arrays with functions it with push and splice will not trigger an update. There are two types of solutions to trigger reactivity. Please note that the performance may vary. One is to add an assignment like this:
numbers.push(numbers.length + 1);
numbers = numbers;
The other is to use assignment statements with the use of alternative javascript operators (like the three-dot spread operator). :
let numbers = [0, 1, 2, 3];
// These will all trigger reactivity.
// Push equilivant.
numbers[numbers.length] = 4;
// [0, 1, 2, 3, 4]
numbers = [...numbers, numbers.length];
// [0, 1, 2, 3, 4, 5]
// Splice, concat or unshift.
numbers = [...numbers.slice(0, 2), ...[2, 3, 4]];
// [0, 1, 2, 3, 4]
numbers = [...numbers, ...numbers];
// [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
Working with calculated data from an object
So let’s say we have some external data source where we have to calculate a link based on an alias:
<script>
import WatchVideo from "./WatchVideo.svelte";
export let video;
let nextVideoLinkId;
nextVideoLinkId = video.id;
if (video.alias) {
videoLinkId = video.alias;
}
</script>
<WatchVideo bind:video />
<a href="/v/{nextVideoLinkId}">Go to next video </a>
This code will work the first time the component is loaded but it will not update the link when the next video is loaded. To fix it we need to wrap the calculation in the special $: syntax:
<script>
import WatchVideo from "./WatchVideo.svelte";
export let video;
let nextVideoLinkId;
$: {
nextVideoLinkId = video.nextVideo.id;
if (video.nextVideo.alias) {
nextVideoLinkId = video.nextVideo.alias;
}
}
</script>
<WatchVideo bind:video />
<a href="/v/{nextVideoLinkId}">Go to next video </a>
Now, every time the video object is updated the next video button link is updated.
Updating a select widget based on external data
To be able to link videos to mathematical subjects we had to create many admin pages. One neat trick is to update the content of a select widget asynchronously with a reactive statement:
<script>
let selectedSubjectId;
$: (async () => {
if (selectedSubjectId) {
// Fetch call to Sapper to retrieve new data.
const res = await fetch(
"/getSubject/?subjectId=" + selectedSubjectId
);
try {
const body = await res.json();
selectedSubject = body;
} catch (err) {
console.error("Error:", err);
}
}
})();
</script>
<label>Select a subject</label>
<select bind:value={selectedSubjectId}>
<option value={selectedSubjectId}>
{selectedSubject.title}
</option>
{#each selectedSubject.children as child}
<option value={child.id}>{child.title}</option>
{/each}
</select>
Discussion
It takes some time to get used to developing reactivity but it is worth it to get adjusted to the concept when you develop with Svelte JS. Sometimes when full reactivity is too complex to implement for non-important end-user pages it is always possible to do a full reload to get fresh data:
location.reload();
Thank you
The blog has taken off quite a bit (almost 150k views) and I am thankful for all readers and especially for the people that donated on BuyMeACofee and those who disabled their adblockers.
1 Comment
Ahmed Aisar · February 16, 2021 at 11:49 am
Thanks man for this! Very helpful.