Skip to content

Commit 6867200

Browse files
authored
fix: keep deriveds reactive after their original parent effect was destroyed (#17171)
Use case: Remote queries that are created on one screen, then are used again on another screen. Original parent effect is destroyed in that case but derived should still be reactive. It wasn't prior to this fix because inside `get` the `destroyed` variable would be true and so deps would not properly be recorded. Fixes sveltejs/kit#14814
1 parent 7fd2d86 commit 6867200

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

.changeset/sad-forks-go.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: keep deriveds reactive after their original parent effect was destroyed

packages/svelte/src/internal/client/reactivity/deriveds.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
STALE_REACTION,
1212
ASYNC,
1313
WAS_MARKED,
14-
CONNECTED
14+
CONNECTED,
15+
DESTROYED
1516
} from '#client/constants';
1617
import {
1718
active_reaction,
@@ -296,7 +297,9 @@ function get_derived_parent_effect(derived) {
296297
var parent = derived.parent;
297298
while (parent !== null) {
298299
if ((parent.f & DERIVED) === 0) {
299-
return /** @type {Effect} */ (parent);
300+
// The original parent effect might've been destroyed but the derived
301+
// is used elsewhere now - do not return the destroyed effect in that case
302+
return (parent.f & DESTROYED) === 0 ? /** @type {Effect} */ (parent) : null;
300303
}
301304
parent = parent.parent;
302305
}

packages/svelte/tests/signals/test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,33 @@ describe('signals', () => {
13911391
};
13921392
});
13931393

1394+
test('derived whose original parent effect has been destroyed keeps updating', () => {
1395+
return () => {
1396+
let count: Source<number>;
1397+
let double: Derived<number>;
1398+
const destroy = effect_root(() => {
1399+
render_effect(() => {
1400+
count = state(0);
1401+
double = derived(() => $.get(count) * 2);
1402+
});
1403+
});
1404+
1405+
flushSync();
1406+
assert.equal($.get(double!), 0);
1407+
1408+
destroy();
1409+
flushSync();
1410+
1411+
set(count!, 1);
1412+
flushSync();
1413+
assert.equal($.get(double!), 2);
1414+
1415+
set(count!, 2);
1416+
flushSync();
1417+
assert.equal($.get(double!), 4);
1418+
};
1419+
});
1420+
13941421
test('$effect.root inside deriveds stay alive independently', () => {
13951422
const log: any[] = [];
13961423
const c = state(0);

0 commit comments

Comments
 (0)