Skip to content

Commit de315d8

Browse files
authored
fix: ensure reactions are kept dirty when marking them again (#11364)
previously a reaction could be marked as DIRTY and subsequently as MAYBE_DIRTY before running, resulting in false negatives. Ensure that DIRTY flag can never be lowered to MAYBE_DIRTY fixes #11363
1 parent 7a3ee6d commit de315d8

File tree

4 files changed

+30
-4
lines changed

4 files changed

+30
-4
lines changed

.changeset/empty-geckos-pretend.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: ensure reactions are kept dirty when marking them again

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ export function invalidate_inner_signals(fn) {
780780

781781
/**
782782
* @param {import('#client').Value} signal
783-
* @param {number} to_status
783+
* @param {number} to_status should be DIRTY or MAYBE_DIRTY
784784
* @param {boolean} force_schedule
785785
* @returns {void}
786786
*/
@@ -793,15 +793,15 @@ export function mark_reactions(signal, to_status, force_schedule) {
793793

794794
for (var i = 0; i < length; i++) {
795795
var reaction = reactions[i];
796+
var flags = reaction.f;
796797

797-
// We skip any effects that are already dirty (but not unowned). Additionally, we also
798+
// We skip any effects that are already dirty. Additionally, we also
798799
// skip if the reaction is the same as the current effect (except if we're not in runes or we
799800
// are in force schedule mode).
800-
if ((!force_schedule || !runes) && reaction === current_effect) {
801+
if ((flags & DIRTY) !== 0 || ((!force_schedule || !runes) && reaction === current_effect)) {
801802
continue;
802803
}
803804

804-
var flags = reaction.f;
805805
set_signal_status(reaction, to_status);
806806

807807
// If the signal is not clean, then skip over it – with the exception of unowned signals that
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
async test({ assert, target }) {
5+
await target.querySelector('button')?.click();
6+
assert.htmlEqual(target.innerHTML, `<button>0</button>`);
7+
}
8+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
let x = $state(1);
3+
let y = $state(1);
4+
let z = $derived(x*y);
5+
</script>
6+
7+
<button onclick={() => {
8+
x = 0;
9+
// reading a derived value and then setting another source contributing to the derived
10+
// resulting in the same value should not prevent pending render effects from updating
11+
z;
12+
y = 0;
13+
}}>{z}</button>

0 commit comments

Comments
 (0)