Arkar Myat

Exploring Svelte Stores

Aug 10, 2023Arkar
Svelte

A useful guide on how to use Stores and state management in Svelte

On this page

In this article, we gonna be talking about Stores and state management in Svelte.

As your application grows, you need to share data across the app. You will need to store data in a way that make it accessible to multiple component in your application. They also need to be reactive, so that any changes made to the data will be automatically shown in the components that are subscribed to the data source. That where store comes in.

Writable stores

Writable stores are a type of store in Svelte that allow you to create a mutable value that can be updated and read from multiple components. When a writable store is updated, all subscribed components will automatically re-render with the updated value.

Here's an example of creating and using a writable store in Svelte:

// store.js
import { writable } from 'svelte/store';

const count = writable(0);

You can now use count in any of your Svelte component or even by regular JavaScript module. To use count in your Svelte component you can subscribe to it by calling the subscribe() method on the store:

// counter.svelte
<script>
	import { counter } from './store.js';
	let count = 0;

	counter.subscribe((value) => {
		count = value;
	});
</script>

<section>
	<h1>{count}</h1>
</section>

To update the value in the store you can use update method which will invoke a callback in which the current value is passed as an argument:

function increment() {
	counter.update((n) => n + 1);
}

function decrement() {
	counter.update((n) => n - 1);
}

To change a value in the writable store, use the set method. This method updates the store with a new value provided as an argument.

// reset counter
function reset() {
	counter.set(0);
}

Svelte updates components using the observer pattern to keep up with changes to the data in a store. This means that when a component subscribes to a store, it starts watching the store. The component is alerted whenever the value of the store changes.

To avoid memory leaks, we need to unsubscribe from stores when you no longer need them. We can do this by calling the unsubscribe() method on the store. It's best to do this in the onDestroy life-cycle method of your Svelte component.

<script>
	import { counter } from './store.js';
	import { onDestroy } from 'svelte';
	let count = 0;

	let unsubscribe = counter.subscribe((value) => {
		count = value;
	});

	function increment() {
		counter.update((n) => n + 1);
	}

	function decrement() {
		counter.update((n) => n - 1);
	}

	onDestroy(unsubscribe);
</script>

Svelte also has an automatic way of subscribing to a store using the $ symbol. Here's an example:

<script>
	import { counter } from './store.js';
	let count = 0;

	$: count = $counter;
</script>

<section>
	<h1>{count}</h1>
	<button on:click={() => counter.update(n => n + 1)}>+</button>
	<button on:click={() => counter.update(n => n - 1)}>-</button>
	<button on:click={() => counter.set(0)}>reset</button>
</section>

In this example, we are using the $ symbol to subscribe to the counter store. This means that the count variable will always reflect the current value of counter, and the component will automatically re-render whenever the value of counter changes.

Readable stores

A readable store in Svelte creates a store whose value cannot be set from 'outside', which cannot be directly changed by a component. Instead, the value of a readable store comes from other stores or external data sources.

Here's an example of creating and using a readable store in Svelte:

// store.js
import { readable } from 'svelte/store';

const randomValue = readable(Math.random(), function start(set) {
	const interval = setInterval(() => {
		set(Math.random());
	}, 1000);

	return function stop() {
		clearInterval(interval);
	};
});

We can use randomValue that generates a random number every second.

// random.svelte
<script>
	import { randomValue } from './store.js';
</script>

<section>
	<h1>{$randomValue}</h1>
</section>

Read-only stores are useful when you want to expose data to multiple components, but you don't want the value of the store to be changed by any of the components.

Read-only store

This function can help you make a store read-only. Even after making it read-only, you can still subscribe to changes from the original store using the new readable store.

import { readonly, writable } from 'svelte/store';
 
const writableStore = writable(1);
const readableStore = readonly(writableStore);
 
readableStore.subscribe(console.log);
 
writableStore.set(2); // console: 2
readableStore.set(2); // ERROR

A simple Example

Here's how to add a simple login authentication to a Svelte app:

Create a writable store called login to track if a user is logged in or not. This store will hold a true or false value indicating the user's login status.

import { writable } from 'svelte/store';

export const login = writable(false);

To get started, make a LoginForm tool that lets users type in their login info. When users submit their info, a function should check if their credentials are correct. If they are, the login store should be set to true.

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

  let username = '';
  let password = '';

  function authenticate() {
    // Check credentials against backend API here
    if (/* credentials are correct */) {
      login.set(true);
    }
  }
</script>

<form on:submit|preventDefault="{authenticate}">
  <label>
    Username:
    <input type="text" bind:value="{username}">
  </label>
  <label>
    Password:
    <input type="password" bind:value="{password}">
  </label>
  <button type="submit">Login</button>
</form>

In your app's main component, subscribe to the login store and conditionally render either the LoginForm component or the app's main content based on the user's login status.

<script>
  import { login } from './stores.js';
  import AuthenticatedContent from './AuthenticatedContent.svelte';
  import UnAuthenticatedContent from './UnAuthenticatedContent.svelte';
</script>

{#if $login}
  <AuthenticatedContent />
{:else}
  <UnAuthenticatedContent />
{/if}

And that's it! We hope you found this article helpful in understanding how stores work in Svelte. By using stores, you can easily manage and share state across your application, making it more efficient and maintainable.

Subscribe to my NewsLetter!

Join my web development newsletter to receive the latest updates, tips, and trends directly in your inbox.