add test + fix spread props

pull/15400/head
Dominic Gannaway 2 years ago
parent 9f21043ca6
commit ed32963d00

@ -42,6 +42,9 @@ export function CallExpression(node, context) {
e.bindable_invalid_location(node);
}
// We need context in case the bound prop is stale
context.state.analysis.needs_context = true;
break;
case '$host':

@ -24,6 +24,7 @@ export const EFFECT_HAS_DERIVED = 1 << 20;
export const STATE_SYMBOL = Symbol('$state');
export const STATE_SYMBOL_METADATA = Symbol('$state metadata');
export const LEGACY_PROPS = Symbol('legacy props');
export const TEARDOWN_PROPS = Symbol('teardown props');
export const LOADING_ATTR_SYMBOL = Symbol('');
export const CTX_CONTAINS_TEARDOWN = 1 << 1;

@ -13,7 +13,7 @@ import {
} from './runtime.js';
import { effect, teardown } from './reactivity/effects.js';
import { legacy_mode_flag } from '../flags/index.js';
import { CTX_CONTAINS_TEARDOWN, CTX_DESTROYED } from './constants.js';
import { CTX_CONTAINS_TEARDOWN, CTX_DESTROYED, TEARDOWN_PROPS } from './constants.js';
import { define_property } from '../shared/utils.js';
/** @type {ComponentContext | null} */
@ -144,6 +144,10 @@ export function push(props, runes = false, fn) {
ctx.f ^= CTX_DESTROYED;
var teardown_props = ctx.tp;
if (TEARDOWN_PROPS in props) {
props[TEARDOWN_PROPS] = teardown_props;
return;
}
// Apply the latest known props before teardown over existing props
for (var key in teardown_props) {
define_property(props, key, {

@ -13,7 +13,13 @@ import { derived, derived_safe_equal } from './deriveds.js';
import { get, captured_signals, untrack } from '../runtime.js';
import { safe_equals } from './equality.js';
import * as e from '../errors.js';
import { CTX_DESTROYED, LEGACY_DERIVED_PROP, LEGACY_PROPS, STATE_SYMBOL } from '../constants.js';
import {
CTX_DESTROYED,
LEGACY_DERIVED_PROP,
LEGACY_PROPS,
STATE_SYMBOL,
TEARDOWN_PROPS
} from '../constants.js';
import { proxy } from '../proxy.js';
import { capture_store_binding } from './store.js';
import { legacy_mode_flag } from '../../flags/index.js';
@ -173,6 +179,12 @@ const spread_props_handler = {
}
},
set(target, key, value) {
// If the spread props have been torn down, then replace the existing props with
// the stale props from the teardown
if (key === TEARDOWN_PROPS) {
target.props = [value];
return true;
}
let i = target.props.length;
while (i--) {
let p = target.props[i];
@ -215,6 +227,9 @@ const spread_props_handler = {
}
},
has(target, key) {
if (key === TEARDOWN_PROPS) {
return true;
}
// To prevent a false positive `is_entry_props` in the `prop` function
if (key === STATE_SYMBOL || key === LEGACY_PROPS) return false;
@ -368,12 +383,6 @@ export function prop(props, key, flags, fallback) {
// source is written to from various places to persist this value.
var inner_current_value = mutable_source(prop_value);
var current_value = derived(() => {
var ctx = component_context;
if (ctx !== null && (ctx.f & CTX_DESTROYED) !== 0) {
return get(inner_current_value);
}
var parent_value = getter();
var child_value = get(inner_current_value);
@ -418,6 +427,12 @@ export function prop(props, key, flags, fallback) {
return value;
}
// If the prop is read, we might need to return the stale value if component ctx has been destroyed
if (current_value.ctx !== null && (current_value.ctx.f & CTX_DESTROYED) !== 0) {
return current_value.v;
}
return get(current_value);
};
}

@ -0,0 +1,5 @@
<script lang="ts">
let { ref = $bindable(null) } = $props();
</script>
<input bind:this={ref} />

@ -0,0 +1,11 @@
import { test } from '../../test';
import { flushSync } from 'svelte';
export default test({
async test({ assert, target, logs }) {
const [btn1] = target.querySelectorAll('button');
btn1.click();
flushSync();
}
});

@ -0,0 +1,19 @@
<script>
import Component from './Component.svelte';
let state = $state({
title: 'foo'
});
</script>
{#if state}
{@const attributes = { title: state.title }}
<Component {...attributes} />
{/if}
<button
onclick={() => {
state = undefined;
}}
>
Del
</button>

@ -61,7 +61,7 @@ export default test({
true,
2,
true,
1,
2,
true
]);
}

Loading…
Cancel
Save