Home > Article > Web Front-end > 'Helper' Varaibles in Svelte 5
Following my recent post Experiences and Caveats of Svelte 5 Migration I would like to highlight some techniques and change of mindset when going from Svelte 4 to Svelte 5.
Svelte 4 uses "magical" $: and let and does all the heavy lifting to make code reactive. We also embraced varaibles reassignment like
<script> let arr = [1, 2, 3] let value = 4 arr = [...arr, value] </script>
instead of methods updating/mutating varaibles like push etc.
I was quite suprprised to re-learn good old JS patterns using Svelte 5.
And I was also probably quite spoiled by let in Svelte 4 , no reasoning about reactivity, it was included if needed. But not all varaibles have to be reactive. Also non reactive variables may be updated in reactive or even "traditional mutating code". The real need for reactive variable is when we use it in UI (when this varaible is rendered in html/page and we need it to update later).
You may encounter erros in Svelte 5 like Cannot assign to derived state, State referenced in its own scope will never update. Did you mean to reference it inside a closure? or derived_references_selfnA derived value cannot reference itself recursively if using Svelte 4 coding style.
Take a look at this example of Svelte 4 style of code:
<script> let value; let derivedArr = [] $: if (value) { derivedArr = [...derivedArr, value] } function random () { value = Math.floor(1 + Math.random() * 10) } </script> <button on:click="{random}">Generate Random Value</button> <p>value: {value}</p> <p>derivedArr: {derivedArr}</p>
DEMO
We have two reactive variables and Svelte 4 solves the updates automatically. We only needed to remember that the right way is by reassigning the variable.
In Svelte 5 we should think a little how to achieve the same result. The two variables we are using are not enough, we need one more, the helper one.
Prefered way is to use a $derived() rune.
<script> let value = $state(); let helperArr = []; let derivedArr = $derived.by(() => { if (value) { helperArr.push(value); return helperArr; } }); function random () { value = Math.floor(1 + Math.random() * 10) } </script> <button onclick="{random}">Generate Random Value</button> <p>value: {value}</p> <p>derivedArr: {derivedArr}</p>
DEMO
If you know easier way to do this let me know.
There is also an $effect() rune way to achieve the same. It might look even simplier but we should avoid effects if possible (mainly Svetlet 5 effects do not run on the server/SSR).
<script> let value = $state(); let helperArr = [] let effectArr = $derived(helperArr); $effect.pre(() => { if (value) { helperArr.push(value) } }) function random () { value = Math.floor(1 + Math.random() * 10) } </script> <button onclick="{random}">Generate Random Value</button> <p>value: {value}</p> <p>effectArr: {effectArr}</p>
DEMO
This is the example how I tried to migrate quite stright forward Svelte 4 page to Svelte 5. It took me a while to rethink the code. This page works as a posts search with a "Load More" functionality (adding results or pagging if a user does not have JS):
Svelte 4
<script> import Icon from '../components/Icon.svelte'; import { enhance } from '$app/forms'; import { tick } from 'svelte'; export let form; export let searchingLang; export let l; let results = []; let previousSearch = ''; let searchTerm; let skip; $: if (!!form && form?.thereIsMore) { searchTerm = form.searchTerm; skip = Number(form?.skip) 20; } $: if (!!form?.searchResultFromAction) { if (previousSearch == form.searchTerm && form.thereWasMore) { results = [...results, ...form.searchResultFromAction]; } else { results = [...form.searchResultFromAction]; previousSearch = form.searchTerm; } } async function intoView(el) { await tick(); if (el.attributes.index.nodeValue == skip - 20 && skip != undefined) { el.scrollIntoView({ behavior: 'smooth' }); } } </script> {#if results.length} <ol> {#each results as item, index} <li use:intoview aria-posinset="{index}"> <!-- users without javascript have calculated order of results within paggination and css disables standard ol ul numbering --> <!-- users with javascript have standard ol ul numbering and loading more feature --> <noscript>{Number(index) 1 Number(form?.skip)}. </noscript> <a href="/act/%7BsearchingLang%7D/%7Bitem.id%7D/present/text">{item.title}</a> </li> {/each} </ol> {#if form?.thereIsMore}
The above is the detailed content of 'Helper' Varaibles in Svelte 5. For more information, please follow other related articles on the PHP Chinese website!