fix: ensure subscriptions are picked up correctly by deriveds

Increment the version to ensure any dependent deriveds are marked dirty when the subscription is picked up again later. If we didn't do this then the comparison of write versions would determine that the derived has a later version than the subscriber, and it would not be re-run.

Fixes #16311
Fixes #15888
pull/16466/head
Simon Holthausen 2 months ago
parent ce4a99ed6d
commit 36e188b5c6

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure subscriptions are picked up correctly by deriveds

@ -82,6 +82,10 @@ export function createSubscriber(start) {
if (subscribers === 0) { if (subscribers === 0) {
stop?.(); stop?.();
stop = undefined; stop = undefined;
// Increment the version to ensure any dependent deriveds are marked dirty when the subscription is picked up again later.
// If we didn't do this then the comparison of write versions would determine that the derived has a later version than
// the subscriber, and it would not be re-run.
increment(version);
} }
}); });
}; };

@ -0,0 +1,45 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
test: ({ assert, target }) => {
const [loading, increment] = target.querySelectorAll('button');
assert.htmlEqual(
target.innerHTML,
`
<div>$value: 0</div>
<div>valueFromStore.current: 0</div>
<div>valueDerivedCurrent: 0</div>
<button>Loading</button>
<button>Increment</button>
`
);
loading.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
`
<div>$value: Loading...</div>
<div>valueFromStore.current: Loading...</div>
<div>valueDerivedCurrent: Loading...</div>
<button>Loading</button>
<button>Increment</button>
`
);
increment.click();
flushSync();
assert.htmlEqual(
target.innerHTML,
`
<div>$value: 1</div>
<div>valueFromStore.current: 1</div>
<div>valueDerivedCurrent: 1</div>
<button>Loading</button>
<button>Increment</button>
`
);
}
});

@ -0,0 +1,36 @@
<script>
import { fromStore, writable } from 'svelte/store';
let isLoading = $state(false);
const value = writable(0);
const valueFromStore = fromStore(value);
const valueDerivedCurrent = $derived(valueFromStore.current);
</script>
<div>
$value: {isLoading ? 'Loading...' : $value}
</div>
<div>
valueFromStore.current: {isLoading ? 'Loading...' : valueFromStore.current}
</div>
<div>
valueDerivedCurrent: {isLoading ? 'Loading...' : valueDerivedCurrent}
</div>
<button
onclick={() => {
isLoading = true;
}}>
Loading
</button>
<button
onclick={() => {
$value++;
isLoading = false;
}}>
Increment
</button>
Loading…
Cancel
Save