diff --git a/.changeset/wicked-zebras-exist.md b/.changeset/wicked-zebras-exist.md new file mode 100644 index 0000000000..f76d77bb90 --- /dev/null +++ b/.changeset/wicked-zebras-exist.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: use correct reaction when lazily creating deriveds inside `SvelteDate` diff --git a/packages/svelte/src/reactivity/date.js b/packages/svelte/src/reactivity/date.js index 2d8de624bc..33da2e1761 100644 --- a/packages/svelte/src/reactivity/date.js +++ b/packages/svelte/src/reactivity/date.js @@ -1,8 +1,7 @@ /** @import { Source } from '#client' */ -import { DESTROYED } from '../internal/client/constants.js'; import { derived } from '../internal/client/index.js'; import { source, set } from '../internal/client/reactivity/sources.js'; -import { get } from '../internal/client/runtime.js'; +import { active_reaction, get, set_active_reaction } from '../internal/client/runtime.js'; var inited = false; @@ -12,6 +11,8 @@ export class SvelteDate extends Date { /** @type {Map>} */ #deriveds = new Map(); + #reaction = active_reaction; + /** @param {any[]} params */ constructor(...params) { // @ts-ignore @@ -43,7 +44,12 @@ export class SvelteDate extends Date { var d = this.#deriveds.get(method); - if (d === undefined || (d.f & DESTROYED) !== 0) { + if (d === undefined) { + // lazily create the derived, but as though it were being + // created at the same time as the class instance + const reaction = active_reaction; + set_active_reaction(this.#reaction); + d = derived(() => { get(this.#time); // @ts-ignore @@ -51,6 +57,8 @@ export class SvelteDate extends Date { }); this.#deriveds.set(method, d); + + set_active_reaction(reaction); } return get(d); diff --git a/packages/svelte/src/reactivity/date.test.ts b/packages/svelte/src/reactivity/date.test.ts index 87bfde41c8..f90c5a102c 100644 --- a/packages/svelte/src/reactivity/date.test.ts +++ b/packages/svelte/src/reactivity/date.test.ts @@ -642,3 +642,33 @@ test('Date methods invoked for the first time in a derived', () => { cleanup(); }); + +test('Date methods shared between deriveds', () => { + const date = new SvelteDate(initial_date); + const log: any = []; + + const cleanup = effect_root(() => { + const year = derived(() => { + return date.getFullYear(); + }); + const year2 = derived(() => { + return date.getTime(), date.getFullYear(); + }); + + render_effect(() => { + log.push(get(year) + '/' + get(year2).toString()); + }); + + flushSync(() => { + date.setFullYear(date.getFullYear() + 1); + }); + + flushSync(() => { + date.setFullYear(date.getFullYear() + 1); + }); + }); + + assert.deepEqual(log, ['2023/2023', '2024/2024', '2025/2025']); + + cleanup(); +});