Skip to content

Commit 794b8f3

Browse files
authored
fix: keep reactions up to date even when read outside of effect (#17295)
In #17105 one line in `update_reaction` was changed that can cause reactivity loss. It checks if the reaction is updated inside of an effect and only then will push to the reactions. The prior version had an additional check to still add to the reactions if there is already at least one reaction on the derived, indicating it is connected. Removing this check fixes #17263 while keeping correctness: a connected derived by definition at least has one reaction and therefore can properly cleanup.
1 parent 1f3f182 commit 794b8f3

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

.changeset/small-llamas-drum.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 reactions up to date even when read outside of effect

packages/svelte/src/internal/client/runtime.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ export function update_reaction(reaction) {
278278
reaction.deps = deps = new_deps;
279279
}
280280

281-
if (is_updating_effect && effect_tracking() && (reaction.f & CONNECTED) !== 0) {
281+
if (effect_tracking() && (reaction.f & CONNECTED) !== 0) {
282282
for (i = skipped_deps; i < deps.length; i++) {
283283
(deps[i].reactions ??= []).push(reaction);
284284
}

packages/svelte/tests/signals/test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,31 @@ describe('signals', () => {
14181418
};
14191419
});
14201420

1421+
test('derived when connected should add new dependency to its reaction even when read outside effect', () => {
1422+
let count_a = state(0);
1423+
let count_b = state(0);
1424+
let which = state(true);
1425+
let double = derived(() => ($.get(which) ? $.get(count_a) * 2 : $.get(count_b) * 2));
1426+
1427+
render_effect(() => {
1428+
$.get(double);
1429+
});
1430+
1431+
return () => {
1432+
flushSync();
1433+
assert.equal($.get(double!), 0);
1434+
1435+
set(which, false);
1436+
$.get(double); // read before render effect has a chance to rerun
1437+
flushSync();
1438+
assert.equal($.get(double!), 0);
1439+
1440+
set(count_b, 1);
1441+
flushSync();
1442+
assert.equal($.get(double!), 2);
1443+
};
1444+
});
1445+
14211446
test('$effect.root inside deriveds stay alive independently', () => {
14221447
const log: any[] = [];
14231448
const c = state(0);

0 commit comments

Comments
 (0)