fix: better handle unowned derived signals (#9832)

* fix: better handle unowned derived signals

* format

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
pull/9841/head
Dominic Gannaway 1 year ago committed by GitHub
parent b20b4617c0
commit d9c250a4bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: better handle unowned derived signals

@ -392,6 +392,8 @@ function remove_consumer(signal, start_index, remove_unowned) {
} }
} }
if (remove_unowned && consumers_length === 0 && (dependency.f & UNOWNED) !== 0) { if (remove_unowned && consumers_length === 0 && (dependency.f & UNOWNED) !== 0) {
// If the signal is unowned then we need to make sure to change it to dirty.
set_signal_status(dependency, DIRTY);
remove_consumer( remove_consumer(
/** @type {import('./types.js').ComputationSignal<V>} **/ (dependency), /** @type {import('./types.js').ComputationSignal<V>} **/ (dependency),
0, 0,

@ -0,0 +1,30 @@
<script context="module">
class Foo {
x = $state(5);
y = $derived(this.x * 2);
}
const foo = new Foo();
let x = $state(2);
let y = $derived(x * 2);
const bar = {
get x() {
return x;
},
set x(val) {
x = val;
},
get y() {
return y;
},
};
</script>
<button onclick={() => foo.x++}>
x: {foo.x}, y: {foo.y}
</button>
<button onclick={() => bar.x++}>
x: {bar.x}, y: {bar.y}
</button>

@ -0,0 +1,71 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
skip_if_hydrate: 'permanent',
async test({ assert, target }) {
let [btn1, btn2] = target.querySelectorAll('button');
const input = target.querySelector('input');
flushSync(() => {
btn1?.click();
});
assert.htmlEqual(
target.innerHTML,
`<input type="checkbox"><button>x:
6,
y:
12</button><button>x:
2,
y:
4</button>`
);
flushSync(() => {
btn2?.click();
});
assert.htmlEqual(
target.innerHTML,
`<input type="checkbox"><button>x:
6,
y:
12</button><button>x:
3,
y:
6</button>`
);
flushSync(() => {
input?.click();
});
assert.htmlEqual(target.innerHTML, `<input type="checkbox">`);
flushSync(() => {
input?.click();
});
[btn1, btn2] = target.querySelectorAll('button');
flushSync(() => {
btn1?.click();
});
flushSync(() => {
btn2?.click();
});
assert.htmlEqual(
target.innerHTML,
`<input type="checkbox"><button>x:
7,
y:
14</button><button>x:
4,
y:
8</button>`
);
}
});

@ -0,0 +1,10 @@
<script>
import Component from "./Component.svelte";
let show = $state(true);
</script>
<input type="checkbox" bind:checked={show} />
{#if show}
<Component/>
{/if}
Loading…
Cancel
Save