Svelte is an up and coming front end framework for developing front end web apps.
It’s simple to use and lets us create results fast.
In this article, we’ll look at how to store shared states in a Svelte store.
Writable Stores
We can add a writable store to store data that are shared by multiple components.
For instance, we can write the following to create a store and use it in a component:
App.svelte
:
<script>
import { count } from "./stores.js";
let countValue;
const unsubscribe = count.subscribe(value => {
countValue = value;
});
const increment = () => {
count.update(n => n + 1);
};
</script>
<button on:click={increment}>Increment</button>
<p>{countValue}</p>
stores.js
:
import { writable } from "svelte/store";
export const count = writable(0);
In the code above, we created a shared writable state in stores.js
called count
.
Then we subscribed to it to get the latest value and set it to count_value
.
We can also call the set
method on count
to reset the value as follows:
App.svelte
:
<script>
import { count } from "./stores.js";
let countValue;
const unsubscribe = count.subscribe(value => {
countValue = value;
});
const increment = () => {
count.update(n => n + 1);
};
const reset = () => {
count.set(0);
};
</script>
<button on:click={increment}>Increment</button>
<button on:click={reset}>Reset</button>
<p>{countValue}</p>
In the code above, we run count.set(0)
when we click on Reset to set the count
state to 0.
We have to call unsubscribe
on the store when the component is destroyed so that we can free up the resources used for the subscription of states.
For instance, we can modify the example above as follows to do that:
App.svelte
:
<script>
import { count } from "./stores.js";
import { onDestroy } from "svelte";
let countValue;
const unsubscribe = count.subscribe(value => {
countValue = value;
});
const increment = () => {
count.update(n => n + 1);
};
onDestroy(unsubscribe);
</script>
<button on:click={increment}>Increment</button>
<p>{countValue}</p>
The code above calls unsubscribe
the function in the destroy
portion of the component lifecycle so that the count
state is no longer subscribed to.
We can replace the store state subscription with the $
. For instance, we can shorten the above example to:
<script>
import { count } from "./stores.js";
import { onDestroy } from "svelte";
const increment = () => {
count.update(n => n + 1);
};
</script>
<button on:click={increment}>Increment</button>
<p>{$count}</p>
We eliminated the code to subscribe and unsubscribe from the count
store and the component still works the same as before.
Read Only Stores
We can make a store that’s read only with the readable
function.
For instance, we can write the following code to make a counter state that’s subscribed to by a component as follows:
stores.js
:
import { readable } from "svelte/store";
export const count = readable(0, set => {
let count = 0;
const interval = setInterval(() => {
set(count);
count++;
}, 1000);
return () => {
clearInterval(interval);
};
});
App.svelte
:
<script>
import { count } from "./stores.js";
</script>
<p>{$count}</p>
In the code above, we call the readable
function in the store. In the second argument, we pass in a callback with the set
function as the parameter, which is called to update the store’s value.
We did that in the setInterval
callback. Then we return another function, which is used to clean up the code when the store is unsubscribed to.
When we run the code, we see a number that’s incremented by 1 every second on the screen.
Store with Derived State
We can call the derived
function to create a store that’s derived from another state.
For instance, we can create a store that emits a value that’s double the count
state that we have above as follows:
stores.js
:
import { readable, derived } from "svelte/store";
export const count = readable(0, set => {
let count = 0;
const interval = setInterval(() => {
set(count);
count++;
}, 1000);
return () => {
clearInterval(interval);
};
});
export const doubleCount = derived(count, $count => $count * 2);
App.svelte
:
<script>
import { count, doubleCount } from "./stores.js";
</script>
<p>{$count}</p>
<p>{$doubleCount}</p>
In the code above, we have the doubleCount
store, which is created by calling the derived
function with the count
store passed in as the first argument and a callback which returns a value that we want to derive from the value emitted by count
as the second argument.
Then we see a number that’s incremented by 1 every second and another that’s incremented by 2 every second.
Store Bindings
We can bind directly to the value of the store if the store is writable.
For instance, we can use bind:value
to bind to the store to the inputted value directly and manipulate the store’s value as follows:
store.js
:
import { writable } from "svelte/store";
export const name = writable("");
App.svelte
:
<script>
import { name } from "./stores.js";
</script>
<input bind:value={$name}>
<button on:click="{() => $name += '.'}">
Add period
</button>
<p>{$name}</p>
In the code above, we change the value of $name
as we type in something in the input, and also when we click Add period.
Then we display the $name
store’s value in the p element.
Conclusion
A store is handy for storing shared states. We make stores that are read-only, writable or are derived from another store.