fix: improve internal proxied state signal heuristic (#11102)

Fixes #11069
pull/11093/head
Dominic Gannaway 3 months ago committed by GitHub
parent d2b6159d2e
commit 48549f7d00
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: improve internal proxied state signal heuristic

@ -1,6 +1,11 @@
import { DEV } from 'esm-env';
import { get, batch_inspect, current_component_context, untrack } from './runtime.js';
import { effect_active } from './reactivity/effects.js';
import {
get,
batch_inspect,
current_component_context,
untrack,
current_effect
} from './runtime.js';
import {
array_prototype,
define_property,
@ -206,7 +211,7 @@ const state_proxy_handler = {
// but only if it's an own property and not a prototype property
if (
s === undefined &&
(effect_active() || updating_derived) &&
(current_effect !== null || updating_derived) &&
(!(prop in target) || get_descriptor(target, prop)?.writable)
) {
s = (metadata.i ? source : mutable_source)(proxy(target[prop], metadata.i, metadata.o));
@ -250,7 +255,10 @@ const state_proxy_handler = {
const has = Reflect.has(target, prop);
let s = metadata.s.get(prop);
if (s !== undefined || (effect_active() && (!has || get_descriptor(target, prop)?.writable))) {
if (
s !== undefined ||
(current_effect !== null && (!has || get_descriptor(target, prop)?.writable))
) {
if (s === undefined) {
s = (metadata.i ? source : mutable_source)(
has ? proxy(target[prop], metadata.i, metadata.o) : UNINITIALIZED
@ -273,7 +281,7 @@ const state_proxy_handler = {
// we do so otherwise if we read it later, then the write won't be tracked and
// the heuristics of effects will be different vs if we had read the proxied
// object property before writing to that property.
if (s === undefined && effect_active()) {
if (s === undefined && current_effect !== null) {
// the read creates a signal
untrack(() => receiver[prop]);
s = metadata.s.get(prop);

@ -0,0 +1,5 @@
<script>
const { settings } = $props();
</script>
Child: {settings.showInRgb}

@ -0,0 +1,22 @@
import { flushSync } from '../../../../src/index-client';
import { test } from '../../test';
export default test({
html: `<button>click true</button> Child: true`,
async test({ assert, target }) {
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.htmlEqual(target.innerHTML, `<button>click false</button> Child: false`);
flushSync(() => {
btn?.click();
});
assert.htmlEqual(target.innerHTML, `<button>click true</button> Child: true`);
}
});

@ -0,0 +1,19 @@
<script context="module">
export const context = $state({
settings: {
showInRgb: true
}
})
</script>
<script>
import Child from './Child.svelte';
const { settings } = context
</script>
<button onclick={() => settings.showInRgb = !settings.showInRgb}>
click {settings.showInRgb}
</button>
<Child settings={settings} />
Loading…
Cancel
Save