SvelteJS Quick Overview of Stores

Quick Overview Svelte JS Stores

Svelte is a radical new approach to building user interfaces.

Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.

This means your bundle will have no dependencies and will come in smaller sizes. Besides that, Svelte’s compiler generates highly optimized code, which means your app will probably have a better overall performance when compared to React, Vue, and Angular.

If you haven’t heard about them, Rich Harris’s videos “Rethinking reactivity” and “The Return of ‘Write Less, Do More’” may be a good place to start. And if you’re interested in learning, you can start by going through this excellent tutorial.

One of the features Svelte provides out of the box is store, a way to share data among components without having to use props and falling into the infamous render props hell.

Svelte’s team have done a great job in providing a very simple and easy way to achieve this. There are two store types: writable and readable. The first one is updatable from the outside, while the other isn’t. For most cases, you’ll end up using the writable type, like in the example below. The code creates a new store with the initial value equal to zero.

we have 3 different type of store

  • writable
  • readable
  • derived store

A Simple writable store

// file store.js
import { writable } from 'svelte/store';
const store = writable(0);
export default store;

This store can be imported and used in any Svelte component.

We can listen to state changes by using the subscribe method and set or update its value with their respective methods.

To subscribe, we provide a callback function that receives the new store state value that can be used to update a component’s local variables. The set method overwrites the store state value with the argument passed to it. The update method receives a callback function as an argument. The callback takes the existing store value as its argument and returns the new value to be set to the store.

You can see these three methods in action in the code below:

// file App.svelte
<script>
import { onDestroy, onMount } from 'svelte';
import store from './store.js'
let counter = 0;
let unsubscribe;
onMount(() => unsubscribe = store.subscribe(state => (counter = state)));

onDestroy(() => {
  if (unsubscribe) {
   unsubscribe()
   }
  })
const reset = () => (store.set(0));
const increment = () => store.update(state => state + 1)
</script>
<main>
    <span>The counter value is {counter}</span>
    <hr />
    <button on:click={increment}>Increment</button>
    <button on:click={reset}>Reset</button>
</main>

In the script tag, first we import the store created earlier. Then, we use two Svelte’s lifecycle events (onMount and onDestroy) to subscribe to the store and update the counter with its value and to unsubscribe from it when the component is destroyed. We also defined two methods — reset, which sets the value back to zero, and increment, which adds one to the store’s value.

In the HTML part, we got a span that shows the counter value ({counter}) and two buttons that fire the methods we created in the script tag.

It’s certainly very easy to understand and use, but, as we can see from the code, all the business logic is written directly in the component, making it difficult to share it with the other components the app may have.

To solve this, we can make use of the excellent documentation provided by Svelte’s team, specially the “Store contract” section. According to the definition, the only requirement is a store must have a subscribe method that returns an unsubscribe method. We already have this implemented in Svelte’s store, so we can use it in our custom store, like in the code below:

// file counter-store.js
import { writable } from 'svelte/store';
const store = writable(0);
const counterStore = {
  subscribe: store.subscribe,
  set: store.set,
  update: store.update,
}; ///
export default counterStore;

Our custom store will work just like Svelte’s writable store, since it’s just returning a object that forwards subscribe, set, and update methods. But to make it better and remove the business logic from our component, we can implement the reset and increment methods inside the store:

// file counter-store.js
import { writable } from 'svelte/store';
const store = writable(0);
const counterStore = {
  subscribe: store.subscribe,
  set: store.set,
  update: store.update,
  reset: store.set(0),
  increment: store.update((state) => state + 1),
};
export default counterStore;

With this, our component can be refactored and simplified:

// file App.svelte

<script>
import { onDestroy, onMount } from 'svelte';
import store from './counter-store.js'
let counter = 0;
let unsubscribe;
onMount(() => unsubscribe = store.subscribe(state => (counter = state)));
onDestroy(() => unsubcribe())
const reset = () => store.reset();
const increment = () => store.increment();
</script>
<main>
    <span>The counter value is {counter}</span>
    <hr />
    <button on:click={increment}>Increment</button>
    <button on:click={reset}>Reset</button>
</main>

And since we’re putting our business logic inside our store, it’s a good idea not to forward the set and update methods to avoid components from messing around with the store data. So our final store code is the one below:

// file counter-store.js
import { writable } from 'svelte/store';
const store = writable(0);
const counterStore = {
  subscribe: store.subscribe,
  reset: store.set(0),
  increment: store.update((state) => state + 1),
};
export default counterStore;

By doing this, any other component that needs to interact with the store data can make it through the reset and increment methods without worrying about the logic behind them.

  • using store with svelte js
  • SPA in Svelte js
  • http requests using svelte js
  • working with forms svelte js
  • using special elements
  • Looking deeper into reactivity
  • deploying app

Sandbox Example

References

Comments