How to Handle Loading State in Svelte: Simple and Effective
loading variable and using conditional blocks like {#if loading} to show a loading indicator. Update this variable before and after async operations to reflect the current state.Why This Happens
When fetching data or performing async tasks, the UI may not show any indication that loading is happening. This confuses users because they see a blank or incomplete screen. The root cause is missing a state variable to track loading and not updating the UI accordingly.
<script>
let data;
async function fetchData() {
data = await fetch('https://api.example.com/data').then(res => res.json());
}
fetchData();
</script>
<main>
<p>{data?.title}</p>
</main>The Fix
Introduce a loading variable set to true before starting the async call and set it to false after data loads. Use Svelte's {#if} block to conditionally show a loading message or spinner while loading is true.
<script>
let data;
let loading = true;
async function fetchData() {
loading = true;
data = await fetch('https://api.example.com/data').then(res => res.json());
loading = false;
}
fetchData();
</script>
<main>
{#if loading}
<p>Loading data, please wait...</p>
{:else}
<p>{data.title}</p>
{/if}
</main>Prevention
Always use a dedicated loading state variable for async operations. Keep UI feedback clear and consistent by showing loading indicators. Use Svelte's reactive statements and conditional blocks to keep code clean. Consider reusable loading components for larger apps.
Related Errors
Common mistakes include not resetting loading after errors, causing the loading message to stay forever. Another is updating UI before data is ready, leading to undefined errors. Always handle errors and update loading accordingly.
<script>
let data;
let loading = true;
let error = null;
async function fetchData() {
loading = true;
error = null;
try {
data = await fetch('https://api.example.com/data').then(res => res.json());
} catch (e) {
error = 'Failed to load data';
} finally {
loading = false;
}
}
fetchData();
</script>
<main>
{#if loading}
<p>Loading...</p>
{:else if error}
<p>{error}</p>
{:else}
<p>{data.title}</p>
{/if}
</main>