If your svelte application relies a lot on store notifications, you must be careful.
Tags: svelte, sveltekit, frontend, sveltestore
Published: 2023-09-22 18:41:08

## TL;DR
Svelte store does not notify subscribers on set/update events if the value of the primitive type is the same.

## The story
<strong>Once upon a time</strong>, the young raccoon was trying to build a "running line" or an element on the page that would print out messages to a user based on some user interactions. Therefore, the application was heavily dependent on the store's event firing system.

And as any young raccoon, our raccoon assumed that if the value is set to a store, the store will notify all subscribers even if the value is the same, right? As it occurred, the raccoon was wrong.

Let's try if different types will behave differently:
Here is a `testNotifyType` function to:
- set up a store
- add subscriber to log updates
- set the value to the store
- update the value
- put object for logs

Demo [REPL](https://svelte.dev/repl/5723c5777e8346658772662e6228ade1?version=4.2.1)
```JavaScript
const testNotifyType = (A, B, comment) => {
  const store = writable();
  let out = {
    value: A,
    type: typeof A,
    logs: [],
    notifiedCounter: 0,
    comment: comment
  };
  store.subscribe((data) => {
    out.notifiedCounter += 1;
    out.logs.push(`notified with: ${String(data)}`);
  })

  out.logs.push(`Trying to set: ${String(A)}`);
  store.set(A);
  store.set(A);
	
  out.logs.push(`Let's try with update with: ${String(B)}`);
  store.update(() => B);
  store.update(() => B);

  output.push(out);
}
```

## [Feel free to skip the code](#object)

### Undefined:

`testNotifyType(undefined, undefined);`

Output:
```
Hello Store!
Can I please have a notifications for every set of "undefined" with type of undefined?
notified with: undefined
Trying to set: undefined
Let's try with update with: undefined
Notified: 1 time, so: No, sorry bro
```

### Boolean

`testNotifyType(true, false);`

```
Can I please have a notifications for every set of "true" with type of boolean?
notified with: undefined
Trying to set: true
notified with: true
Let's try with update with: false
notified with: false
Notified: 3 times, so: No, sorry bro
```

### Number

`testNotifyType(0, 1);`

```
Can I please have a notifications for every set of "0" with type of number?
notified with: undefined
Trying to set: 0
notified with: 0
Let's try with update with: 1
notified with: 1
Notified: 3 times, so: No, sorry bro
```

### BigInt

`testNotifyType(BigInt(2), BigInt(3));`

```
Can I please have a notifications for every set of "2" with type of bigint?
notified with: undefined
Trying to set: 2
notified with: 2
Let's try with update with: 3
notified with: 3
Notified: 3 times, so: No, sorry bro
```

### String

`testNotifyType("a", "b");`

```
Can I please have a notifications for every set of "a" with type of string?
notified with: undefined
Trying to set: a
notified with: a
Let's try with update with: b
notified with: b
Notified: 3 times, so: No, sorry bro
```

### Symbol

`testNotifyType(Symbol("a"), Symbol("b"));`

```
Can I please have a notifications for every set of "Symbol(c)" with type of symbol?
notified with: undefined
Trying to set: Symbol(c)
notified with: Symbol(c)
Let's try with update with: Symbol(d)
notified with: Symbol(d)
Notified: 3 times, so: No, sorry bro
```

### As you can see undefined, boolean, number, bigint, string, symbol type didn't notify subscribers. 
Should we try an object?

### Object

`testNotifyType({}, {}, "What about object?");`

```
What about object?
Can I please have a notifications for every set of "[object Object]" with type of object?
notified with: undefined
Trying to set: [object Object]
notified with: [object Object]
notified with: [object Object]
Let's try with update with: [object Object]
notified with: [object Object]
notified with: [object Object]
Notified: 5 times, so: Yes!
```

### Array?

`testNotifyType([4, 3], [1, 2], "What about array?");`

```
What about array?
Can I please have a notifications for every set of "4,3" with type of object?
notified with: undefined
Trying to set: 4,3
notified with: 4,3
notified with: 4,3
Let's try with update with: 1,2
notified with: 1,2
notified with: 1,2
Notified: 5 times, so: Yes!
```

## And it worked!<a name="object"></a>

As we can see above the store will notify subscribers for the same value only in case of the `object` type, but not [primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive) types.

## Why?

In case you are as curious as a young raccoon to dig deeper into the [sveltejs/svelte repo](https://github.com/sveltejs/svelte), then:
We can see [writable](https://github.com/sveltejs/svelte/blob/fa89421301f949c83d9e5e34a1f6e215137cdf4c/packages/svelte/src/runtime/store/index.js#L36)
store does <strong>safe_not_equal</strong> check before any actions.

```javascript
export function writable(value, start = noop) {
	/** @type {import('./public.js').Unsubscriber} */
	let stop;
	/** @type {Set<import('./private.js').SubscribeInvalidateTuple<T>>} */
	const subscribers = new Set();
	/** @param {T} new_value
	 * @returns {void}
	 */
	function set(new_value) {
		if (safe_not_equal(value, new_value)) {
			value = new_value;
```

And the [code](https://github.com/sveltejs/svelte/blob/fa89421301f949c83d9e5e34a1f6e215137cdf4c/packages/svelte/src/runtime/internal/utils.js#L66) for the `safe_not_equal` function:
```
/** @returns {boolean} */
export function safe_not_equal(a, b) {
	return a != a ? b == b : a !== b || (a && typeof a === 'object') || typeof a === 'function';
}
```
Function will return true for the same values only if an `object` or `function` were passed.

I think it does make sense now.

## Workaround

For my "running line" I've wrapped the value of the stores into the object:

```javascript
queueWritable: Writable<string[]>;
mutexWritable: Writable<{ mutex: boolean }>;
waitTimeWritable: Writable<{ time: number }>;
message: Writable<{ message: string }>;
```

And setting the value by:
```javascript
this.mutexWritable.set({ mutex: true });
```

## I hope you've learned something from this "article", but if you didn't, have a good day)

Of course, a mature raccoon already knew this feature of the svelte store because raccoon reads the source code instead of documentation, but I felt like it was worth sharing, even if a single young raccoon will find it helpful.

So, be careful and be smarter than our young raccoon🦝.

Be safe.

Try the demo [REPL](https://svelte.dev/repl/5723c5777e8346658772662e6228ade1?version=4.2.1)

## Provoking question:
### The world, what is the matter with you?