diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md index e254be754f..ef64091ca3 100644 --- a/packages/svelte/CHANGELOG.md +++ b/packages/svelte/CHANGELOG.md @@ -1,5 +1,11 @@ # svelte +## 5.34.9 + +### Patch Changes + +- fix: ensure unowned deriveds can add themselves as reactions while connected ([#16249](https://github.com/sveltejs/svelte/pull/16249)) + ## 5.34.8 ### Patch Changes diff --git a/packages/svelte/package.json b/packages/svelte/package.json index 17a3e980c4..1d26663143 100644 --- a/packages/svelte/package.json +++ b/packages/svelte/package.json @@ -2,7 +2,7 @@ "name": "svelte", "description": "Cybernetically enhanced web apps", "license": "MIT", - "version": "5.34.8", + "version": "5.34.9", "type": "module", "types": "./types/index.d.ts", "engines": { diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 56bc157f33..d057bfdf0d 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -294,7 +294,12 @@ export function update_reaction(reaction) { reaction.deps = deps = new_deps; } - if (!skip_reaction) { + if ( + !skip_reaction || + // Deriveds that already have reactions can cleanup, so we still add them as reactions + ((flags & DERIVED) !== 0 && + /** @type {import('#client').Derived} */ (reaction).reactions !== null) + ) { for (i = skipped_deps; i < deps.length; i++) { (deps[i].reactions ??= []).push(reaction); } diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js index ec0126b17d..1c0aed6e87 100644 --- a/packages/svelte/src/version.js +++ b/packages/svelte/src/version.js @@ -4,5 +4,5 @@ * The current version, as set in package.json. * @type {string} */ -export const VERSION = '5.34.8'; +export const VERSION = '5.34.9'; export const PUBLIC_VERSION = '5'; diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 78d7919e0f..719c936df0 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -112,6 +112,45 @@ describe('signals', () => { }; }); + test('unowned deriveds are not added as reactions but trigger effects', () => { + var obj = state(undefined); + + class C1 { + #v = state(0); + get v() { + return $.get(this.#v); + } + set v(v: number) { + set(this.#v, v); + } + } + + return () => { + let d = derived(() => $.get(obj)?.v || '-'); + + const log: number[] = []; + assert.equal($.get(d), '-'); + + let destroy = effect_root(() => { + render_effect(() => { + log.push($.get(d)); + }); + }); + + set(obj, new C1()); + flushSync(); + assert.equal($.get(d), '-'); + $.get(obj).v = 1; + flushSync(); + assert.equal($.get(d), 1); + assert.deepEqual(log, ['-', 1]); + destroy(); + // ensure we're not leaking reactions + assert.equal(obj.reactions, null); + assert.equal(d.reactions, null); + }; + }); + test('derived from state', () => { const log: number[] = [];