I'm working with the following code in Svelte 3.55.0.
First, I have an empty webpage because I have no items
to render. Then, onMount
fires and I fetch
some items
from an API. Finally, the items get rendered.
<script>
import { slide } from "svelte/transition";
import { onMount } from "svelte";
// Initially we have no items.
let items = [];
let id = 0;
onMount(() => {
// Fetch items from API.
items = [
{id: id, name: `item ${id++}`},
{id: id, name: `item ${id++}`},
{id: id, name: `item ${id++}`},
];
});
function addItem() {
items = [
...items,
{id: id, name: `item ${id++}`},
];
}
</script>
<div>
<button on:click={addItem}>add</button>
{#each items as it (it.id)}
<div transition:slide>
<p>{it.id} {it.name}</p>
</div>
{/each}
</div>
The problem is that fetch
gets like 50 items and I don't want to play transitions for any of them. However, I do want transitions when individual items are added or removed only inside of the list.
Is there a way to achieve this effect?
Sandbox: https://codesandbox.io/s/blue-shape-njxx9o?file=/App.svelte
This could be achieved by adding an #if
block around the main element so it's only rendered after the items are fetched and adding the |local
flag to the transition - tutorial
(Like here the transition only seem to play correctly if the outer element has display:flex
)
<script>
import { slide } from "svelte/transition";
import {onMount} from 'svelte'
let items = [];
let id = 0;
let itemsFetched = false
onMount(async() => {
setTimeout(() => {
items = [
{id: id, name: `item ${id++}`},
{id: id, name: `item ${id++}`},
{id: id, name: `item ${id++}`},
];
console.log('fetched')
itemsFetched = true
},1000)
})
function addItem() {
items = [
...items,
{id: id, name: `item ${id++}`},
];
}
</script>
<button on:click={addItem}>add</button>
{#if itemsFetched}
<div id="outer">
{#each items as it (it.id)}
<div transition:slide|local={{duration: 2000}}>
<p>{it.id} {it.name}</p>
</div>
{/each}
</div>
{/if}
<style>
#outer {
display: flex;
flex-direction: column;
}
</style>
Alternative with #await
REPL
<script>
import { slide } from "svelte/transition";
import {onMount} from 'svelte'
let items = [];
let id = 0;
function fetchItems() {
return new Promise(res => {
setTimeout(() => {
items = [
{id: id, name: `item ${id++}`},
{id: id, name: `item ${id++}`},
{id: id, name: `item ${id++}`},
];
console.log('fetched')
res()
},1000)
})
}
function addItem() {
items = [
...items,
{id: id, name: `item ${id++}`},
];
}
</script>
<button on:click={addItem}>add</button>
{#await fetchItems() then _}
<div id="outer">
{#each items as it (it.id)}
<div transition:slide|local={{duration: 2000}}>
<p>{it.id} {it.name}</p>
</div>
{/each}
</div>
{/await}
<style>
#outer {
display: flex;
flex-direction: column;
}
</style>