DEV Community

Cover image for If your svelte application relies a lot on store notifications, you must be careful.
Artur Linnik
Artur Linnik

Posted on

If your svelte application relies a lot on store notifications, you must be careful.

TL;DR

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

The story

Once upon a time, 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

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);
}
Enter fullscreen mode Exit fullscreen mode

Feel free to skip the code

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

And it worked!

As we can see above the store will notify subscribers for the same value only in case of the object type, but not primitive types.

Why?

In case you are as curious as a young raccoon to dig deeper into the sveltejs/svelte repo, then:
We can see writable
store does safe_not_equal check before any actions.

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;
Enter fullscreen mode Exit fullscreen mode

And the code 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';
}
Enter fullscreen mode Exit fullscreen mode

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:

queueWritable: Writable<string[]>;
mutexWritable: Writable<{ mutex: boolean }>;
waitTimeWritable: Writable<{ time: number }>;
message: Writable<{ message: string }>;
Enter fullscreen mode Exit fullscreen mode

And setting the value by:

this.mutexWritable.set({ mutex: true });
Enter fullscreen mode Exit fullscreen mode

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

Provoking question:

The world, what is the matter with you?

Top comments (0)