We have already covered the Writable and Readable store in the previous articles. In this article, we will learn how to make use of derived store from Svelte. If you want a refresher on those topic, have a look at the following two topics
https://www.eternaldev.com/blog/introduction-to-svelte-stores/
https://www.eternaldev.com/blog/introduction-to-svelte-readable-store/
When to use Svelte derived store
When you want to perform on client side filtering based on user input, then using a derived store can be a good option. Store the actual data in the store and then use another derived store to store just the filtered options.
In general, if you want to derive another data from a store value and want that value to update every time the store updates, you can use derived store
Let’s skip these generic definition and see a practical example. We will implement a client side search on a list of post we have fetched.
What are we building today ?
Building a home page which will have a list of post and then a search box to filter the post based on the search. We will pull the data from the Placeholder API which will return a total of 200 posts. When the user enter the text in the search box, we will use the derived store to filter the posts and show the filtered post to the user.
Create a derived store
Creating a derived store can be done after import derived
from svelte/store
. It needs to be dependent on either a writable or readable store and the value of this store is recalculated when one of its dependency changes
Create a new file called postStore.svelte
inside the new folder called store
import { writable, derived} from "svelte/store";
import type { Writable } from "svelte/store";
type Post = {
title: string;
body: string;
}
export const allPostStore: Writable<Post[]> = writable([]);
export const filteredText: Writable<string> = writable("");
export const filteredPostStore = derived([allPostStore, filteredText], ([$allPostStore, $filteredText]) => {
return $allPostStore.filter((item) => item.title.includes($filteredText));
})
Let’s breakdown the above code
- We are importing the needed items from
svelte/store
- We are creating a
Post
type which fits the response form the API (placeholder post API) - Create
allPostStore
writable store which will be used to store the list of post from the API - Create
filteredText
writable store which will store the value of the text entered in Search input text - Finally, create the derived store, which will take the other two stores as dependencies as the first argument in array. Second argument is function which will have access to the dependent stores.
- Then we can filter the all post list and only include the post which contains the search text in the title.
Create a component to use derived store
Create a new file called PostDisplay.svelte
and add the following code
<script lang="ts">
import {onMount} from "svelte";
import {allPostStore, filteredPostStore, filteredText} from '../store/postStore';
let postPromise;
onMount(() => {
postPromise = fetch('https://jsonplaceholder.typicode.com/posts').then((data) => data.json()).then((post) => {
$allPostStore = post;
});
})
</script>
- Import all the store from the
../store/postStore
. This will give us access to the store to read and write content - Add the
onMount
life cycle method which will be called on the component being rendered on the screen - Call the Placeholder API to fetch a list of posts and then store the data in the
$allPostStore
store.
Now we have access to all the post. When the user enters the search text, we can do front-end filtering of the list and display only the post which match the search text. This is where our derived store helps.
We store the post value in the $allPostStore
but we can use the derived store variable to display the post. This means that the original list of all the post is not disturbed and we get a new filtered list every time the search text changes. Sweet!
<h1>Posts</h1>
{#await postPromise}
<h2>Loading....</h2>
{:then post}
<input type="text" placeholder="Search..." bind:value={$filteredText} name="search"/>
<div class="post-container">
{#each $filteredPostStore as post}
<h3>{post.title}</h3>
<p>{post.body}</p>
{/each}
</div>
{:catch error}
<h3>Error while loading the data</h3>
{/await}
- We are using the
await
svelte syntax to make our life easier and then show the loading and error message. - Input field value is being linked to
$filteredText
which is the store variable usingbind:value
. So it automatically updates the store value. Wow! - Using the
#each
syntax, we can iterate through the derived store$filteredPostStore
and display the post in a list
Top comments (0)