Skip to content

Commit

Permalink
fix: improve internal proxied state signal heuristic (#11102)
Browse files Browse the repository at this point in the history
Fixes #11069
  • Loading branch information
trueadm authored Apr 9, 2024
1 parent d2b6159 commit 48549f7
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-mice-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte": patch
---

fix: improve internal proxied state signal heuristic
18 changes: 13 additions & 5 deletions packages/svelte/src/internal/client/proxy.js
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
const { settings } = $props();
</script>

Child: {settings.showInRgb}
Original file line number Diff line number Diff line change
@@ -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`);
}
});
Original file line number Diff line number Diff line change
@@ -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} />

0 comments on commit 48549f7

Please sign in to comment.