Svelte is a crazy good compiler that generates boosted vanilla JavaScript.
It's readable and straightforward, and it has an unusual approach for common patterns you might dig in.
State management in Svelte
Svelte does a lot of magic behind the scene. I usually don't consider "magic" as a good thing in code, but, IMHO, it makes sense here.
I like the philosophy: it does not create elements when it's not needed. Sometimes, it breaks nodes into separate nodes for more efficient updates.
Besides, the compiler has a particular way to handle the app state. It provides pretty cool bindings to manage state within the component hierarchy.
However, not everything is a parent-child relationship. You often need global data. That's when stores can be helpful.
Stores and subscription in general
Stores store values. They are objects.
Stores necessarily implement a subscribe()
method. Every time a value changes, the subscribe()
method notifies all elements connected to the store. They can also have a set()
method to add values.
Getting started with Svelte stores
Svelte has writable
and readable
stores. Readable stores are read-only, unlike writable stores.
Let's write a store in a file called actresses.js
(you can read the whole demo code in this repl):
import { writable } from "svelte/store";
let actresses = [
{ "name": "Naomi Watts", "oscars": 0 },
{ "name": "Scarlett Johansson", "oscars": 0 },
{ "name": "Charlize Theron", "oscars": 1 },
];
let { subscribe, update } = writable(actresses);
let add = actress => update(actresses => {
return [...actresses, actress];
});
export default {
subscribe,
add
}
Not all stores should be writable. If it does not make sense, don't let any component set/update values in your store:
import { readable } from "svelte/store";
If you want to further, please see this excellent example of readable stores
Populate and update data
To use our store of actresses, it's pretty straightforward:
<script>
import actresses from "./actresses.js";
</script>
<pre>
{JSON.stringify($actresses)}
</pre>
We use the syntactic sugar $
. Svelte provides this handy hack to bind things quickly, but we'll see that later in the post.
If you need to update something, you can leverage the benefits of writable
:
<script>
import actresses from "./actresses.js";
actresses.add({ "name": "AI", "oscars": 93 })
</script>
<pre>
{JSON.stringify($actresses, null, 2)}
</pre>
Automatic subscription and $
Adding $
before any Svelte variable makes your variable an object with a subscribe()
and an unsubscribe()
method by default.
This way, you don't have to write the same code repeatedly. The following code does not need to handle any mount/unmount event. It's automagic
:
<script>
import my_store from "./my_store.js"; // assuming you have a writable store in this file
let handleClick = () => $my_store++;
</script>
<button on:click={ handleClick }>Click</button>
<p>{$my_store}</p>
And you can add an "if block" to conditionally display the counter:
{#if $my_store > 0 }
<p>{$my_store}</p>
{/if }
Complete code is available in repl
N.B: Please make sure you use $
for stores only, not DOM references. Svelte does not allow this kind of usage.
Derived stores
Svelte allows for using values from one or several stores inside another store.
It's called derived
, and it might be helpful when you don't want to update values manually when other state changes.
It could prevent unnecessary complexity in individual stores. Honestly, I never had to use it, but it's available if you need it.
Wrap up
The need for app-wide data, outside of the component hierarchy, is not uncommon, and Svelte stores are ready for that usage.
Cherry on top, Svelte allows creating and using stores effortlessly thanks to an auto-subscribe mechanism.
Top comments (0)