What are Stores in Svelte?

In large applications, passing the state of the application through the component is cumbersome. Often, several Svelte components require the same data (For example, notification or list of cart items). To achieve this feat, Svelte has stores. You can relate it (Svelte stores) similar to Redux in React.

In this article, we learn about:

  1. Stores
  2. Types of stores
    a. Writable stores
    b. Readable stores
    c. Derived stores

What you should know before further reading?

What is Store?

A store is an object that holds data and gains admittance to that data from different parts of the application. Svelte stores are a built-in functionality that facilitates an elegant way to manage the state of the application. They're reactive, which means that they'll update components whenever the data changes across the application. Inshort, stores are global data that hold values or an object. Components subscribe to stores and receive notifications when their values changes.

Writable Stores

Every store has a subscribe method that returns a function allow us to unsubscribe.  
Writable stores allow components to modify their data. It also has set and update method addition to the subscribe method.

Let's say we have login file that has login key and we want to use it in our app. Create a file login.js under the src folder.

import { writable } from "svelte/store";

export const loginKey = writable('something-secret-is-the-login-key')

In the above code, we define a loginKey variable and put it under the writable(). It is just to define that our loginKey variable is writable in nature.

And then create a file WritableStoreComponent.svelte under the src folder and add the following code.

<script>
    import { loginKey } from './login.js'

    let login_key;

    loginKey.subscribe(value => {
        login_key = value
    });



</script>

<div>
    <h2 style="color: darkgreen"> { login_key }  </h2>


</div>

In this file, we simply imported the loginKey from the login.js javascript file. We already discussed, to every store has the subscribe function. We use the subscribe function and assign the value to login_key variable. And then we render the variable under the <div> element.

Last thing, we need to do is in the App.svelte

<script>

    import WritableComponent from "./WritableComponent.svelte";

</script>

<main>
    <p> Writable Store Example. </p>
    <hr/>

    <div>
        <br />
        <WritableComponent />
    </div>

</main>

<style>
	main {
		text-align: center;
		padding: 1em;
		max-width: 240px;
		margin: 0 auto;
	}


	@media (min-width: 640px) {
		main {
			max-width: none;
		}
	}
</style>

If you go the web page, we'll see.


We see the secret key that we defined in the login.js file. But this is not the example of the writable store. In general login keys has expiration date and it needs to be updated from time to time basis. How we can do that?

We'll use set method to update the loginKey variable. Add  the following line loginKey.set('updated-something-secret-login-key') to the WritableStoreComponent and you'll see the updated key on the webpage.

<script>
    import { loginKey } from './login.js'

    let login_key;

    loginKey.subscribe(value => {
        login_key = value
    });

    loginKey.set('updated-something-secret-login-key')


</script>

<div>
    <h2 style="color: darkgreen"> { login_key }  </h2>
</div>

Readable Store

As the name implies, it's a read-only store. In Svelte, other components cannot update the readable stores. Unlike writable stores, there's no set() or update() method. We must initialise the value of the Readable store values at the time of creation.

In short, we can say that it is an abstraction around writable stores in which set() and update() method are hidden from the enduser.

Let's create another file date.js under the src folder.

import { readable } from "svelte/store";

export const date = readable(0, (set) => {
    const interval = setInterval( () => {
        set( new Date() );
    }, 1000 );

    return () => clearInterval( interval )
});

Here is a simple example, where we can set the date in the store. Please take a look at readable() function. It looks complicated at first look but actually it is not.

As it's a readable store, we can't change the value. We just use it in our App.svelte file. Add the following code just below the <WritableComponent>.

// Under the script
import { date } from "./date";

// Under the main

<hr />

    <p> <strong> Readable Store Example. </strong> </p>
    <hr/>

    <div>
        <br />
        <div>
            { $date.toLocaleString() }
        </div>
    </div>

So the complete code is

<script>

    import WritableComponent from "./WritableComponent.svelte";

    import { date } from "./date";

</script>

<main>
    <p> Writable Store Example. </p>
    <hr/>

    <div>
        <br />
        <WritableComponent />
    </div>

    <hr />

    <p> <strong> Readable Store Example. </strong> </p>
    <hr/>

    <div>
        <br />
        <div>
            { $date.toLocaleString() }
        </div>
    </div>

</main>

<style>
	main {
		text-align: center;
		padding: 1em;
		max-width: 240px;
		margin: 0 auto;
	}


	@media (min-width: 640px) {
		main {
			max-width: none;
		}
	}
</style>

Visit the page and we'll see


Derived Stores

The Derived store values depend on other stores. They'll update themselves when the value they are derived from changes. They always listen to other stores and then return to a computed value as a readable store.

We'll modify the code of the date.js and import the derived function. And then we calculate the total time spends on that page.

import { readable, derived } from "svelte/store";

export const date = readable(0, (set) => {
    const interval = setInterval( () => {
        set( new Date() );
    }, 1000 );

    return () => clearInterval( interval )
});

const startDate = new Date()

export const totalTime = derived( date, $time => {
    return Math.round(( $time  - startDate ) / 1000 )
})
You'll find this example in the Svelte Docs also but you need to add return before Math.round(). Otherwise it will not work.

And then in the App.svelte

// Under script
import { date, totalTime } from "./date";

// Before </main>
<p> <strong> Derived Store Example. </strong> </p>
    <hr/>

    <div>
        <br />
        <div>
            Total Seconds { $totalTime }
        </div>
    </div>

Here we can see the Total Seconds added from the derived stores. In this article we see, how convenient it is to use the stores in Svelte. They are fairly simple to use and provides great flexibility to share the data between the components. There is one more type of stores and i.e. is Custom Stores, we'll cover it separately in our next article.