DEV Community

Bigi Lui
Bigi Lui

Posted on • Updated on • Originally published at bigi.dev

Svelte Reactivity and Stores

I don't code in Svelte for my day job, so I only get to work with it on my hobby projects. Like most people, I only occasionally have time to work on them. I will have an ongoing project that I just randomly take a hiatus from because life, and then a month/a few months would pass by (or maybe even a year later), I get back to work on it.

Svelte is an intuitive framework and once you learn the basics, it's easy to navigate a Svelte codebase and get things done. Occasionally there are quirks that catch me off-guard, though.

One of the things that have caught me multiple times now, after taking a break and coming back to a project, is how Svelte handles reactivity with its Stores.

Let's say you have some Writable Stores like this, set up in a stores.js file:

import { writable } from 'svelte/store';

export const status_message = writable('Howdy');
export const game_state = writable({});
export const cards = writable([]);
Enter fullscreen mode Exit fullscreen mode

You use these stores normally in your other Svelte components. So you have things like this:

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

  status_message.set('Hello!');
</script>

<div>{$status_message}</div>
Enter fullscreen mode Exit fullscreen mode

All good so far. Let's say though in some cases you put an object or an array into a Writable Store, like the example above with game_state and cards. Because usually you intend to update only some subset of the fields within the object, you may write your code like this in a component that updates it:

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

  $game_state.current_turn = 2;
</script>

<div>Current turn: {$game_state.current_turn}</div>
Enter fullscreen mode Exit fullscreen mode

And you'll find that game_state does not seem to be updated, even though you're using it as an Auto-subscribed Store by virtue of using $.

You have to use .set()

The gotcha here is that reactivity is triggered by the .set() call, not simply the data in the Writable Store being updated. So the way to do something like the example above would be:

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

  $game_state.current_turn = 2;
  game_state.set($game_state);

  // Alternatively, use .update() instead of .set()
</script>

<div>Current turn: {$game_state.current_turn}</div>
Enter fullscreen mode Exit fullscreen mode

When you think about the internal workings of Svelte, it makes sense; the specific functions of .set() or .update() on a Writable Store is what kicks off re-evaluation and reactivity based on the value of that store.

When I'm just coding though, I tend to think of a Store as simply a variable that can be accessed globally from anywhere in the frontend app and that changes to it immediately reflect everywhere else. Because of that, I tend to forget what I really should do to kick off a reactive update, especially when what's in the Store is an object or array.

Discussion (2)

Collapse
thevediwho profile image
Vaibhav Dwivedi

Great article. In what cases, should we be using the stores?

Collapse
bigi profile image
Bigi Lui Author

I think stores are great as a global state holder for your application (usually SPA, but can be just a simple app without pages too).

I think of it as something like a global variable accessible by all components within your Svelte app, and that its value changes are automatically/reactively reflected in all your components (when done right ;).