Skip to content

Commit 6bd6f09

Browse files
authored
fix: ensure derived is detected as dirty correctly (#11496)
Deriveds where under certain conditions not detected as dirty correctly. The reason is that a transitive check_dirtiness call could update the flag of a derived, even if the condition doesn't ulimately result to true. That's why the check for "is now dirty" needs to be moved out of the inner if block. Fixes #11481 This may also fix a yet undetected overfiring bug in the "is unowned" case because the previous inner "is now dirty?" check didn't take unowned into account.
1 parent d86b052 commit 6bd6f09

File tree

4 files changed

+32
-5
lines changed

4 files changed

+32
-5
lines changed

.changeset/shiny-melons-love.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 derived is detected as dirty correctly

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,6 @@ export function check_dirtiness(reaction) {
197197

198198
if (!is_dirty && check_dirtiness(/** @type {import('#client').Derived} */ (dependency))) {
199199
update_derived(/** @type {import('#client').Derived} **/ (dependency), true);
200-
201-
// `signal` might now be dirty, as a result of calling `update_derived`
202-
if ((reaction.f & DIRTY) !== 0) {
203-
return true;
204-
}
205200
}
206201

207202
if (is_unowned) {
@@ -227,6 +222,9 @@ export function check_dirtiness(reaction) {
227222
reactions.push(reaction);
228223
}
229224
}
225+
} else if ((reaction.f & DIRTY) !== 0) {
226+
// `signal` might now be dirty, as a result of calling `check_dirtiness` and/or `update_derived`
227+
return true;
230228
}
231229
}
232230
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: `<button>00</button>`,
5+
6+
async test({ assert, target }) {
7+
const btn = target.querySelector('button');
8+
await btn?.click();
9+
10+
assert.htmlEqual(target.innerHTML, `<button>01</button>`);
11+
}
12+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
let shouldShow01 = $state(false);
3+
4+
let der1 = $derived(shouldShow01)
5+
// der2 must depend on der1 and its output shouldn't change
6+
let der2 = $derived(typeof der1 === "string");
7+
let der3 = $derived(der2 ? "1" : "0");
8+
// der3 must be read before der1
9+
let der4 = $derived(der3 + (der1 ? "1" : "0"));
10+
</script>
11+
12+
<button onclick={() => (shouldShow01 = true)}>{der4}</button>

0 commit comments

Comments
 (0)