Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

svelte stores are greedy and have no equivalent of <svelte:options immutable={true} /> #10453

Open
WHenderson opened this issue Feb 12, 2024 · 1 comment
Labels
feature request runtime Changes relating to runtime APIs

Comments

@WHenderson
Copy link

Describe the problem

Currently, sveltes stores use a greedy comparator to determine if a value has changed:

/**
 * @param {any} a
 * @param {any} b
 * @returns {boolean}
 */
export function safe_not_equal(a, b) {
	// eslint-disable-next-line eqeqeq
	return a != a
		? // eslint-disable-next-line eqeqeq
			b == b
		: a !== b || (a && typeof a === 'object') || typeof a === 'function';
}

This makes sense as a default as it matches the nature of reactive blocks in svelte 4.

Svelte 4 also supports immutable reactivity (<svelte:options immutable={true} />). see: example

It would be useful if the stores had a similar parallel, allowing the ability to specify an alternative equality checker such as a strict equality checker.

Describe the proposed solution

Update the store api/implementation to allow a configurable comparison function which would override the default safe_not_equal.

e.g.

/**
 * @param {any} a
 * @param {any} b
 * @returns {boolean}
 */
export function strict_not_equal(a, b) {
	return a !== a;
}

possible apis:

extend the current implementation

const w1 = writable({ value: 1 }, { comparator: strict_not_equal });
const w2 = writable({ value: 1 }, () => {}, { comparator: strict_not_equal })
const r1 = readable({ value: 1 }, { comparator: strict_not_equal })
const r2 = readable({ value: 1 }, () => {}, { comparator: strict_not_equal })
const d1 = derived(w1, w1 => {}, undefined, { comparator: strict_not_equal })
const d2 = derived([w1,w2], ([w1, w2]) => {}, undefined, { comparator: strict_not_equal })

offer an alternative import

import { readable, writable, derived } from 'svelte/immutable-stores';

Importance

nice to have

@rmunn
Copy link
Contributor

rmunn commented Feb 27, 2024

This was the root cause of a bug I spent a while tracking down in one of my projects, where I was firing off an API request when a derived store updated, and I was seeing it fire off twice in the space of a few milliseconds. The API request happened to have a bug that made it non-idempotent, but it took me a while to realize that when the store's value updated to an object with identical values as the previous value, the derived store was triggering an update.

@Conduitry Conduitry added the runtime Changes relating to runtime APIs label Feb 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request runtime Changes relating to runtime APIs
Projects
None yet
Development

No branches or pull requests

4 participants