Components are the primary reason of using any modern JavaScript framework because it lets you organize code and have your concerns in one place.
If you ever used classes you can think of components as new instances of a class that can be used as a blueprint to have its own independent state.
It’s easy to get carried away with components so in general don’t look for what to turn into a component but write everything inside a single file until it becomes hard to manage and you start noticing repeating parts.
You might have an <Artist />
component:
<Artist />
components gets passed theartistName
property<Album />
component hasalbumTitle
andalbumTracks
property passed to<AlbumTrack />
<AlbumTrack />
component hastrack
andlength
properties but also aplaying
state
The filename can be whatever but a capitalised tag such as <Artist />
indicates to Svelte that something is a component. You import another Svelte component using the import Component as './Component'
syntax.
Pretend that artists
is some data we fetched as a JSON response from the Spotify API.
App.svelteCopy
<script>
import Artist from './Artist.svelte'
import Album from './Album.svelte'
let artists = [
{
name: 'Fleetwood Mac',
albums: [
{
name: 'Tango in the Night',
year: 1987,
tracks: [
{ title: 'Big Love', length: '3:37' },
{ title: 'Seven Wonders', length: '3:38' },
{ title: 'Everywhere', length: '3:48' },
{ title: 'Caroline', length: '3:50' },
{ title: 'Tango in the Night', length: '3:56' },
{ title: 'Mystified', length: '3:08' },
],
},
],
},
]
</script>
{#each artists as artist}
<Artist artistName={artist.name} />
{#each artist.albums as album}
<Album
albumTitle={album.name}
albumTracks={album.tracks}
/>
{/each}
{/each}
The <Artist />
component takes an artistName
prop. To define something as a prop that’s passed in to your component you use the export let prop
syntax. You can define multiple props on the same line such as export let prop1, prop2
.
Artist.svelteCopy
<script>
export let artistName
</script>
<h1>{artistName}</h1>
The <Album />
component imports <AlbumTrack />
and loops over the tracks. The {...track}
syntax is just spreading the track
props which is equivalent to title={title} length={length}
. If your props share the same name as the value you can do {title} {length}
.
Album.svelteCopy
<script>
import AlbumTrack from './AlbumTrack.svelte'
export let albumTitle
export let albumTracks
let playing
function setPlaying(track) {
playing = track
}
</script>
<h2>{albumTitle}</h2>
<ul>
{#each albumTracks as track}
<AlbumTrack {setPlaying} {playing} {...track} />
{/each}
</ul>
We’re passing setPlaying
to the child component so we can set the currently playing song and check if currentlyPlaying
is equal to the current track.
The <AlbumTrack />
component applies a .playing
style using the class:
directive based on what song is playing which is shorter than using a ternary inside an expression class={playing === title ? 'playing' : ''}
.
AlbumTrack.svelteCopy
<script>
export let setPlaying
export let playing
export let title
export let length
</script>
<li class:playing={playing === title}>
<button on:click={() => setPlaying(title)}>▶️</button>
<span>{title}</span>
<span>🕒️ {length}</span>
</li>
<style>
.playing {
color: teal;
}
</style>
We can also use a reactive statement $: playing = playing === title
for playing
and since it matches the class name we want to apply we can simplify the code and write class:playing
.
AlbumTrack.svelteCopy
<script>
export let setPlaying
export let playing
export let title
export let length
$: playing = playing === title
</script>
<li class:playing>
<button on:click={() => setPlaying(title)}>▶️</button>
<span>{title}</span>
<span>🕒️ {length}</span>
</li>
<style>
.playing {
color: teal;
}
</style>
Leave a Reply