pull/16278/head
Rich Harris 3 months ago
parent 79e7203c3b
commit 05636d309b

@ -12,7 +12,7 @@ import {
import { get_descriptor, is_function } from '../../shared/utils.js'; import { get_descriptor, is_function } from '../../shared/utils.js';
import { set, source, update } from './sources.js'; import { set, source, update } from './sources.js';
import { derived, derived_safe_equal } from './deriveds.js'; import { derived, derived_safe_equal } from './deriveds.js';
import { get, untrack } from '../runtime.js'; import { get, is_destroying_effect, untrack } from '../runtime.js';
import * as e from '../errors.js'; import * as e from '../errors.js';
import { LEGACY_PROPS, STATE_SYMBOL } from '#client/constants'; import { LEGACY_PROPS, STATE_SYMBOL } from '#client/constants';
import { proxy } from '../proxy.js'; import { proxy } from '../proxy.js';
@ -366,7 +366,12 @@ export function prop(props, key, flags, fallback) {
// prop is written to, but there's no binding, which means we // prop is written to, but there's no binding, which means we
// create a derived that we can write to locally // create a derived that we can write to locally
var d = ((flags & PROPS_IS_IMMUTABLE) !== 0 ? derived : derived_safe_equal)(getter); var overridden = false;
var d = ((flags & PROPS_IS_IMMUTABLE) !== 0 ? derived : derived_safe_equal)(() => {
overridden = false;
return getter();
});
// Capture the initial value if it's bindable // Capture the initial value if it's bindable
if (bindable) get(d); if (bindable) get(d);
@ -376,6 +381,7 @@ export function prop(props, key, flags, fallback) {
const new_value = mutation ? get(d) : runes && bindable ? proxy(value) : value; const new_value = mutation ? get(d) : runes && bindable ? proxy(value) : value;
set(d, new_value); set(d, new_value);
overridden = true;
if (fallback_value !== undefined) { if (fallback_value !== undefined) {
fallback_value = new_value; fallback_value = new_value;
@ -384,7 +390,10 @@ export function prop(props, key, flags, fallback) {
return value; return value;
} }
if (has_destroyed_component_ctx(d)) { // special case — avoid recalculating the derived if
// we're in a teardown function and the prop
// was overridden locally
if (is_destroying_effect && overridden) {
return d.v; return d.v;
} }

@ -0,0 +1,15 @@
<script>
let { message, count } = $props();
$effect(() => () => {
console.log(count, message);
});
</script>
<p>{count}</p>
<!-- we need these so that the props are made into deriveds -->
<button disabled onclick={() => {
count += 1;
message += '!';
}}>update</button>

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

@ -0,0 +1,13 @@
<script>
import Component from "./Component.svelte";
let message = $state('hello');
let count = $state(0);
</script>
<button onclick={() => count++}>{count}</button>
<button onclick={() => message = message === 'hello' ? 'goodbye' : 'hello'}>{message}</button>
{#if count < 2 && message === 'hello'}
<Component {count} {message} />
{/if}
Loading…
Cancel
Save