Skip to content

Commit 7bef596

Browse files
authored
fix: ensure reactions are correctly attached for unowned deriveds (#15158)
* fix: ensure reactions are correctly attached for unowned deriveds * tune
1 parent 970aa7c commit 7bef596

File tree

6 files changed

+51
-4
lines changed

6 files changed

+51
-4
lines changed

.changeset/loud-cars-scream.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: ensure reactions are correctly attached for unowned deriveds

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

+9-4
Original file line numberDiff line numberDiff line change
@@ -802,12 +802,19 @@ function process_effects(effect, collected_effects) {
802802
if (is_branch) {
803803
current_effect.f ^= CLEAN;
804804
} else {
805+
// Ensure we set the effect to be the active reaction
806+
// to ensure that unowned deriveds are correctly tracked
807+
// because we're flushing the current effect
808+
var previous_active_reaction = active_reaction;
805809
try {
810+
active_reaction = current_effect;
806811
if (check_dirtiness(current_effect)) {
807812
update_effect(current_effect);
808813
}
809814
} catch (error) {
810815
handle_error(error, current_effect, null, current_effect.ctx);
816+
} finally {
817+
active_reaction = previous_active_reaction;
811818
}
812819
}
813820

@@ -952,13 +959,11 @@ export function get(signal) {
952959
var derived = /** @type {Derived} */ (signal);
953960
var parent = derived.parent;
954961

955-
if (parent !== null) {
962+
if (parent !== null && (parent.f & UNOWNED) === 0) {
956963
// If the derived is owned by another derived then mark it as unowned
957964
// as the derived value might have been referenced in a different context
958965
// since and thus its parent might not be its true owner anymore
959-
if ((parent.f & UNOWNED) === 0) {
960-
derived.f ^= UNOWNED;
961-
}
966+
derived.f ^= UNOWNED;
962967
}
963968
}
964969

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
let { value = $bindable() } = $props()
3+
</script>
4+
5+
<button onclick={() => value = 'a'}>change</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
let {disabled = false} = $props()
3+
</script>
4+
5+
{disabled}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
let [btn1, btn2] = target.querySelectorAll('button');
7+
8+
btn1?.click();
9+
flushSync();
10+
11+
btn2?.click();
12+
flushSync();
13+
14+
assert.htmlEqual(target.innerHTML, `<button>change</button><button>change</button>\nfalse`);
15+
}
16+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script>
2+
import Child2 from './Child2.svelte'
3+
import Child from './Child.svelte'
4+
let loginname = $state('')
5+
let password = $state('')
6+
</script>
7+
8+
<Child bind:value={loginname} />
9+
<Child bind:value={password} />
10+
<Child2 disabled={!loginname || !password} />
11+

0 commit comments

Comments
 (0)