Notes: Svelte - Logic Blocks
Third page containing notes about Svelte. As before, I’ll keep the structure the same. Quotes will be quoted via >
and explanation will follow. Notes are separated using ---
horizontal lines
Notes
{#each expression as name}...{:else}...{/each}
Svelte has syntax for taking a list and turning each item into some HTML block. It looks like this (or a minor variation). This particular variant was interesting to me because I had didn’t realize there could be an {:else}
block. This is used in cases where the list is undefined or null or empty. This is handy because it saves an {#if}
check that would otherwise surround the {#each}
block.
So, to make this explicit (because I like to see examples). Without else
:
{#if myList.length > 0}
{#each myList as item}
// show blocks for items
{/each}
{:else}
// show blocks here when list is empty
{/if}
With else
:
{#each myList as item}
show blocks here for items
{:else}
// show blocks here when list is empty
{/each}
Not a huge win, but decreases the number of conditionals and amount of nesting when using lists. Pretty nice.
Since Svelte 4 it is possible to iterate over iterables like
Map
orSet
. Iterables need to be finite and static (they shouldn’t change while being iterated over). Under the hood, they are transformed to an array usingArray.from
before being passed off to rendering. If you’re writing performance-sensitive code, try to avoid iterables and use regular arrays as they are more performant.
Oh, interesting. This is another bit of syntactic sugar that maybe won’t come up a lot, but is really nice to know about.
{#await expression}...{:then name}...{:catch name}...{/await}
{#await}
expressions seem great. They remind me of how MvRx (an Android UI library) would model data fetched from the network. MvRx used Kotlin to create a set of sealed classes that model the data as Loading
, Data
, or Error
states. This mimics the structure of JS promises we see here.
This structure does introduce some confusion for me around component best practices. In the Android world, the community has coalesced around having the UI layer (the same layer as Components in Svelte, seemingly) be a pure/dumb function of state. State comes in that consists of String
, Int
, Boolean
types, and they are mapped directly into what is rendered on screen by the UI layer. There’s no logic, no network calls, etc. As such, there’s limited need for testing the UI layer, which is great because that is the hardest layer to test (historically).
The confusion for me with Svelte and {#await}
blocks then boils down to whether Svelte Components are expected to do things like make network requests and update their own state. On the one hand, that wouldn’t be super unreasonable. And the existence of things like {#await}
seems to imply that is expected. On the other hand, this creates some concerns about managing complexity. For example, if components manage their own data fetching/updating over the network, you could quickly run into cross-component synchronization challenges.
Overall, I would expect that the Svelte people would say “you can have it both ways.” You can structure Components as pure functions of state objects in large, complicated systems that benefit from that kind of approach. And you can have small, complete Components that know how to fetch/update data when that makes sense.
{#key expression}...{/key}
Key blocks destroy and recreate their contents when the value of an expression changes.
This is useful if you want an element to play its transition whenever a value changes.
Interesting. I know Svelte has great support for basic animations. I didn’t know that {#key}
could be used to reliably trigger those animations. Good use case.
When used around components, this will cause them to be reinstantiated and reinitialised.
{#key value} <Component /> {/key}
Good thing to note, as it relates to the Component lifecycle. Using {#key}
will cause a Component to call onMount
again when the keyed data changes.