Understanding the {#await ...} block in Svelte
From my research, I've found that the {#await ...} block in Svelte to be one of the less used and understood features of the framework.
While it's not the most common feature, it's still a very useful one. Let's dig into it.
Promises in Svelte
It's not uncommon to see a Svelte component that looks like this:
<script lang="ts">
let data: any;
fetch('https://pokeapi.co/api/v2/pokemon?limit=1000')
.then((res) => res.json())
.then((res) => {
data = res;
});
</script>
{#if data}
{#each data.results as result}
<p>{result.name}</p>
{/each}
{/if}We define a reactive variable data and then fetch some data from an API. Once the data is fetched, we assign it to the data variable and then use it in our markup.
Now, let's say we want to fetch some data from an API, but we want to show a loading indicator while the data is being fetched.
We could potentially do something like this:
{#if data}
{#each data.results as result}
<p>{result.name}</p>
{/each}
{:else}
<p>Loading...</p>
{/if}So far, so good. Now, let's say we also want to display errors if the API call fails. We will need to add another then() chain to our promise:
<script lang="ts">
let data: any;
let error = false;
fetch('https://pokeapi.co/api/v2/pokemon?limit=1000')
.then((res) => res.json())
.then((res) => {
data = res;
})
.catch(() => {
error = true;
});
</script>
{#if error}
<p>Something went wrong</p>
{/if}This is one of the way you'd handle promises in Svelte. But there's a better way. And you'll find it very useful when you start having a bunch of promises and data fetching in your components.
Enter the {#await ...} block
Before I explain anything, let's take a look at what the previous example would look like using the {#await ...} block:
<script lang="ts">
const getPokemon = async () => {
const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=1000');
const data = await res.json();
return data;
};
</script>
{#await getPokemon()}
<p>fetching</p>
{:then data}
{#each data.results as result}
<p>{result.name}</p>
{/each}
{:catch error}
<p>Something went wrong</p>
{/await}This code is very self-explanatory, but let's go over it anyway.
We start by defining an
asyncfunction that will fetch the data from the API. This function will return a promise.We then use the
{#await ...}block to wait for the promise to resolve. While the promise is pending, the code inside the block will be rendered.When the promise resolves, the code inside the
{:then ...}block will be rendered. The resolved value of the promise will be passed to the block.If the promise rejects, the code inside the
{:catch ...}block will be rendered. The rejected value of the promise will be passed to the block.
As you can see, the {#await ...} block is a very powerful, improves our code lisibility and makes it easier to handle loading states and errors while fetching data.
Overall, we are saving a lot of lines of code, and it's much easier to read and understand what's going on.