Reputation: 2845
To show a loading spinner while waiting for a web request response, I'd use the following very simple if statement with my spinner component:
{#if waitingForAPIResponse}
<Spinner></Spinner>
{/if}
What is a good approach to only show the Spinner component after, say, 200ms of waiting? I intuitively want to set up a timer, but I bet there's a better svelte approach.
Upvotes: 5
Views: 6400
Reputation: 4296
You could also include the waiting logic inside a Loader
component
<!-- Loader.svelte -->
<script>
import { onDestroy } from "svelte";
let show = false;
const timeoutId = setTimeout(()=>show=true, 400);
onDestroy(()=>clearTimeout(timeoutId));
</script>
{#if show}
<Spinner/>
{/if}
and then just use it like this
{#if waitingForAPIResponse}
<Loader/>
{/if}
it won't render the <Spinner/>
until the timeout is completed.
You can customize lots of things with this approach.
You could make the inner <Spinner/>
dynamic by using slots
...
{#if show}
<slot>
<Spinner/>
</slot>
{/if}
and now you could use it like this
{#if waitingForAPIResponse}
<Loader>
<Spinnerv2/>
</Loader>
{/if}
Of course, it would not be a "Loader" anymore, more like a "DelayedRenderer"
Upvotes: 3
Reputation: 16451
The most dynamic way to do this would be to add another promise to the mix.
<script>
const wait = () => new Promise((res) => setTimeout(res , 1000))
</script>
{#await APIRequest}
{#await wait()}
<span>Not going to take long</span>
{:then a}
<span>Taking a while</span>
{/await}
{:then data}
...
{/await}
Important here is that the 'inner await' calls a function, this will trigger the creation of a new promise everytime it is rendered (for instance if for some reason your retrigger the APIRequest).
This can also be expanded to be flexibile in how long you wait by simple passing an argument to wait
:
const wait = delay => new Promise((res) => setTimeout(res, delay))
Upvotes: 6
Reputation: 14873
I guess there is no easiest way to produce an event after x second with setTimeout
. So I would just use another variable timerOK
that is initially false
and after 200ms true
:
<script>
import {onMount} from 'svelte'
let response = null
let timerOK = false
$: isLoading = !(response && timerOK)
onMount(() => {
setTimeout(() => {
timerOK = true
}, 1200)
fetch('...').then(callResponse => {
// do your stuffs
response = 'OK'
})
})
</script>
{#if isLoading}
...Loading
{:else}
{response}
{/if}
Have a look at the REPL.
Upvotes: 2