fix: ensure async initial store value is noticed (#12486)

* fix: ensure async initial store value is noticed

fixes #12341

* fix another case
pull/12487/head
Simon H 1 year ago committed by GitHub
parent ea22840e8c
commit 4b8674fe02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure async initial store value is noticed

@ -97,11 +97,7 @@ export function set(source, value) {
// reactions as we only allocate and assign the reactions after the signal
// has fully executed. So in the case of ensuring it registers the reaction
// properly for itself, we need to ensure the current effect actually gets
// scheduled. i.e:
//
// $effect(() => x++)
//
// We additionally want to skip this logic when initialising store sources
// scheduled. i.e: `$effect(() => x++)`
if (
is_runes() &&
current_effect !== null &&

@ -31,18 +31,19 @@ export function store_get(store, store_name, stores) {
set(entry.source, undefined);
entry.unsubscribe = noop;
} else {
var initial = true;
var is_synchronous_callback = true;
entry.unsubscribe = subscribe_to_store(store, (v) => {
if (initial) {
// if the first time the store value is read is inside a derived,
// we will hit the `state_unsafe_mutation` error if we `set` the value
if (is_synchronous_callback) {
// If the first updates to the store value (possibly multiple of them) are synchronously
// inside a derived, we will hit the `state_unsafe_mutation` error if we `set` the value
entry.source.v = v;
initial = false;
} else {
set(entry.source, v);
}
});
is_synchronous_callback = false;
}
}

@ -0,0 +1,10 @@
import { test } from '../../test';
export default test({
mode: ['client'],
async test({ assert, target }) {
assert.htmlEqual(target.innerHTML, ' / ');
await new Promise((r) => setTimeout(r, 110));
assert.htmlEqual(target.innerHTML, '42 / 42');
}
});

@ -0,0 +1,19 @@
<script>
function store() {
return {
subscribe: (cb) => {
setTimeout(() => {
cb(42);
}, 100);
return () => {};
}
};
}
const value1 = store();
const value2 = store();
const derivedValue = $derived($value1);
</script>
{$value2} / {derivedValue}

@ -1,7 +1,18 @@
<script>
import { writable } from "svelte/store";
let store = writable('store');
let name = $derived($store); // store signal is updated during reading this, which normally errors, but shouldn't for stores
<script>
import { writable } from 'svelte/store';
let store1 = writable('store');
let store2 = {
subscribe: (cb) => {
cb('...');
cb('Hello');
return () => {};
}
};
// store signal is updated during reading this, which normally errors, but shouldn't for stores
let name = $derived($store1);
let hello = $derived($store2);
</script>
<h1>Hello {name}</h1>
<h1>{hello} {name}</h1>

Loading…
Cancel
Save