diff --git a/.changeset/swift-oranges-cover.md b/.changeset/swift-oranges-cover.md new file mode 100644 index 000000000000..fd1b94cfd9b6 --- /dev/null +++ b/.changeset/swift-oranges-cover.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +Fix components mounted via mount() during onMount() that not properly update when using signals provided as input of the mount() function. diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index fd5706eaf270..79cb0f2227f3 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -8,7 +8,7 @@ import { is_array, object_prototype } from '../shared/utils.js'; -import { state as source, set } from './reactivity/sources.js'; +import { source, state, set } from './reactivity/sources.js'; import { STATE_SYMBOL } from '#client/constants'; import { UNINITIALIZED } from '../../constants.js'; import * as e from './errors.js'; @@ -35,7 +35,7 @@ export function proxy(value) { /** @type {Map>} */ var sources = new Map(); var is_proxied_array = is_array(value); - var version = source(0); + var version = state(0); var stack = DEV && tracing_mode_flag ? get_stack('CreatedAt') : null; var reaction = active_reaction; @@ -56,9 +56,9 @@ export function proxy(value) { }; if (is_proxied_array) { - // We need to create the length source eagerly to ensure that + // We need to create the length source (state) eagerly to ensure that // mutations to the array are properly synced with our proxy - sources.set('length', source(/** @type {any[]} */ (value).length, stack)); + sources.set('length', state(/** @type {any[]} */ (value).length, stack)); } return new Proxy(/** @type {any} */ (value), { @@ -79,7 +79,7 @@ export function proxy(value) { var s = sources.get(prop); if (s === undefined) { - s = with_parent(() => source(descriptor.value, stack)); + s = with_parent(() => state(descriptor.value, stack)); sources.set(prop, s); } else { set( @@ -98,7 +98,7 @@ export function proxy(value) { if (prop in target) { sources.set( prop, - with_parent(() => source(UNINITIALIZED, stack)) + with_parent(() => state(UNINITIALIZED, stack)) ); update_version(version); } @@ -178,7 +178,7 @@ export function proxy(value) { (active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) ) { if (s === undefined) { - s = with_parent(() => source(has ? proxy(target[prop]) : UNINITIALIZED, stack)); + s = with_parent(() => state(has ? proxy(target[prop]) : UNINITIALIZED, stack)); sources.set(prop, s); } @@ -202,22 +202,22 @@ export function proxy(value) { if (other_s !== undefined) { set(other_s, UNINITIALIZED); } else if (i in target) { - // If the item exists in the original, we need to create a uninitialized source, - // else a later read of the property would result in a source being created with + // If the item exists in the original, we need to create a uninitialized source (state), + // else a later read of the property would result in a source (state) being created with // the value of the original item at that index. - other_s = with_parent(() => source(UNINITIALIZED, stack)); + other_s = with_parent(() => state(UNINITIALIZED, stack)); sources.set(i + '', other_s); } } } - // If we haven't yet created a source for this property, we need to ensure + // If we haven't yet created a source (state) for this property, we need to ensure // 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) { if (!has || get_descriptor(target, prop)?.writable) { - s = with_parent(() => source(undefined, stack)); + s = with_parent(() => state(undefined, stack)); set( s, with_parent(() => proxy(value)) diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js new file mode 100644 index 000000000000..f3dd65eded06 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/_config.js @@ -0,0 +1,34 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, logs }) { + const button = target.querySelector('button'); + + assert.htmlEqual( + target.innerHTML, + ` + +
+

First if block:

+ First: true +

Second if block:

+ Second: true +
+ ` + ); + + flushSync(() => button?.click()); + + assert.htmlEqual( + target.innerHTML, + ` + +
+

First if block:

+

Second if block:

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte new file mode 100644 index 000000000000..0408b6218aba --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/main.svelte @@ -0,0 +1,22 @@ + + + +
diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js new file mode 100644 index 000000000000..7bb247167036 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/module.svelte.js @@ -0,0 +1,19 @@ +import { mount } from 'svelte'; +import Nested from './nested.svelte'; + +export function mountComponentWithContext(target) { + const stateObject = $state({ showText: true }); + + mount(Nested, { + target, + props: {}, + context: new Map([['stateContext', stateObject]]) + }); + + return { + getShowText: () => stateObject.showText, + setShowText: (newShowText) => { + stateObject.showText = newShowText; + } + }; +} diff --git a/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte new file mode 100644 index 000000000000..92c6d800ae2f --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/mount-component-in-onmount-with-context-with-state/nested.svelte @@ -0,0 +1,15 @@ + + +

First if block:

+{#if stateObjectFromContext.showText === true} + First: {stateObjectFromContext.showText} +{/if} + +

Second if block:

+{#if stateObjectFromContext.showText === true} + Second: {stateObjectFromContext.showText} +{/if}