fix: ensure SvelteDate cached methods have correct reactive context (#14525)

* fix: ensure SvelteDate cached methods have no reactive context

* fix: ensure SvelteDate cached methods have no reactive context

* fix

* lint

* use active reaction at time of instance creation

* tweak changeset

* Update packages/svelte/src/internal/client/dom/elements/bindings/shared.js

Co-authored-by: Paolo Ricciuti <ricciutipaolo@gmail.com>

---------

Co-authored-by: Dominic Gannaway <dg@domgan.com>
Co-authored-by: Paolo Ricciuti <ricciutipaolo@gmail.com>
pull/14530/head
Rich Harris 3 weeks ago committed by GitHub
parent 39275684e5
commit 2f8eda94f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: use correct reaction when lazily creating deriveds inside `SvelteDate`

@ -1,8 +1,7 @@
/** @import { Source } from '#client' */ /** @import { Source } from '#client' */
import { DESTROYED } from '../internal/client/constants.js';
import { derived } from '../internal/client/index.js'; import { derived } from '../internal/client/index.js';
import { source, set } from '../internal/client/reactivity/sources.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; var inited = false;
@ -12,6 +11,8 @@ export class SvelteDate extends Date {
/** @type {Map<keyof Date, Source<unknown>>} */ /** @type {Map<keyof Date, Source<unknown>>} */
#deriveds = new Map(); #deriveds = new Map();
#reaction = active_reaction;
/** @param {any[]} params */ /** @param {any[]} params */
constructor(...params) { constructor(...params) {
// @ts-ignore // @ts-ignore
@ -43,7 +44,12 @@ export class SvelteDate extends Date {
var d = this.#deriveds.get(method); 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(() => { d = derived(() => {
get(this.#time); get(this.#time);
// @ts-ignore // @ts-ignore
@ -51,6 +57,8 @@ export class SvelteDate extends Date {
}); });
this.#deriveds.set(method, d); this.#deriveds.set(method, d);
set_active_reaction(reaction);
} }
return get(d); return get(d);

@ -642,3 +642,33 @@ test('Date methods invoked for the first time in a derived', () => {
cleanup(); 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();
});

Loading…
Cancel
Save