My code computes the number of characters the user has input. I allows users to save the entered text to localstorage and then when they visit the page the character count is shown. This is how I load the data:
// App.Svelte
<script>
import Description from "./lib/Description.svelte";
import Save from "./lib/Save.svelte";
import { description, extraSections } from "./lib/store";
import { onMount } from "svelte";
onMount(() => {
if (localStorage.getItem("extraSections") != null) {
$extraSections = JSON.parse(localStorage.getItem("extraSections"));
}
$description = localStorage.getItem("description");
});
</script>
<div class="container">
<div class="inputs" id="inputs">
<Title />
<Description bind:text={$description} />
{#each $extraSections as section (section.id)}
<Description heading="Additional Section" bind:text={section.value} />
{/each}
...
The problem I was facing was that my Description component wasn't showing the count for the text entered from the localstorage since my function to compute that ran only on keyup
:
// Description.Svelte
<script>
let count = 0;
let words = 0;
function handleKeyUp() {
count = text.length;
words = text.trim().split(/\s+/).length;
if (text.length == 0) {
words = 0;
}
}
export let text = "";
export let heading = "Description";
</script>
<div>
<label for="title">{heading}</label>
<textarea
on:keyup={handleKeyUp}
id="description"
name="description"
bind:value={text}
></textarea>
<p>Characters: {count}</p>
<p>Words: {words}</p>
</div>
To fix this I did this made the handleKeyUp
function reactive to a change in value of text
using the $:
syntax:
<script>
let count = 0;
let words = 0;
function handleKeyUp(dummy) {
count = text.length;
words = text.trim().split(/\s+/).length;
if (text.length == 0) {
words = 0;
}
}
// whenever text changes (when loading from localstorage)
// we want to rerun handleKeyUp
$: handleKeyUp(text);
export let text = "";
export let heading = "Description";
</script>
I wanted to ask if this is a valid practice in Svelte? Or is there a better way to do this? Thanks!
This adds noise and can be confusing, so I would not recommend it.
The most common approach in Svelte 3/4 is to use a sequence expression instead:
$: text, handleKeyUp();
But I would generally recommend defining the function reactively, so the dependencies in the function body are captured:
$: handleKeyUp = () => {
// ...
};
$: handleKeyUp();
(Neither approach is necessary in Svelte 5, where dependencies are tracked across function boundaries at runtime.)