Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/wicked-zebras-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: use correct reaction when lazily creating deriveds inside `SvelteDate`
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function listen(target, events, handler, call_handler_immediately = true)
/**
* @template T
* @param {() => T} fn
* @returns {T}
*/
export function without_reactive_context(fn) {
var previous_reaction = active_reaction;
Expand Down
14 changes: 11 additions & 3 deletions packages/svelte/src/reactivity/date.js
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -12,6 +11,8 @@ export class SvelteDate extends Date {
/** @type {Map<keyof Date, Source<unknown>>} */
#deriveds = new Map();

#reaction = active_reaction;

/** @param {any[]} params */
constructor(...params) {
// @ts-ignore
Expand Down Expand Up @@ -43,14 +44,21 @@ 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
return date_proto[method].apply(this, args);
});

this.#deriveds.set(method, d);

set_active_reaction(reaction);
}

return get(d);
Expand Down
30 changes: 30 additions & 0 deletions packages/svelte/src/reactivity/date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
Loading