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

@ -1,5 +1,5 @@
/** @import { ComponentContext } from '#client' */
/** @import { Derived, Source } from './types.js' */
/** @import { Derived, Effect, Source } from './types.js' */
import { DEV } from 'esm-env';
import {
PROPS_IS_BINDABLE,
@ -12,9 +12,15 @@ import {
import { get_descriptor, is_function } from '../../shared/utils.js';
import { set, source, update } from './sources.js';
import { derived, derived_safe_equal } from './deriveds.js';
import { get, is_destroying_effect, untrack } from '../runtime.js';
import {
active_effect,
get,
is_destroying_effect,
set_active_effect,
untrack
} from '../runtime.js';
import * as e from '../errors.js';
import { LEGACY_PROPS, STATE_SYMBOL } from '#client/constants';
import { DESTROYED, LEGACY_PROPS, STATE_SYMBOL } from '#client/constants';
import { proxy } from '../proxy.js';
import { capture_store_binding } from './store.js';
import { legacy_mode_flag } from '../../flags/index.js';
@ -94,7 +100,7 @@ export function rest_props(props, exclude, name) {
/**
* The proxy handler for legacy $$restProps and $$props
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number> }>}}
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number>, parent_effect: Effect }>}}
*/
const legacy_rest_props_handler = {
get(target, key) {
@ -104,6 +110,11 @@ const legacy_rest_props_handler = {
},
set(target, key, value) {
if (!(key in target.special)) {
var previous_effect = active_effect;
try {
set_active_effect(target.parent_effect);
// Handle props that can temporarily get out of sync with the parent
/** @type {Record<string, (v?: unknown) => unknown>} */
target.special[key] = prop(
@ -115,6 +126,9 @@ const legacy_rest_props_handler = {
/** @type {string} */ (key),
PROPS_IS_UPDATED
);
} finally {
set_active_effect(previous_effect);
}
}
target.special[key](value);
@ -153,7 +167,19 @@ const legacy_rest_props_handler = {
* @returns {Record<string, unknown>}
*/
export function legacy_rest_props(props, exclude) {
return new Proxy({ props, exclude, special: {}, version: source(0) }, legacy_rest_props_handler);
return new Proxy(
{
props,
exclude,
special: {},
version: source(0),
// TODO this is only necessary because we need to track component
// destruction inside `prop`, because of `bind:this`, but it
// seems likely that we can simplify `bind:this` instead
parent_effect: /** @type {Effect} */ (active_effect)
},
legacy_rest_props_handler
);
}
/**
@ -376,6 +402,12 @@ export function prop(props, key, flags, fallback) {
// Capture the initial value if it's bindable
if (bindable) get(d);
var parent_effect = /** @type {Effect} */ (active_effect);
if (!parent_effect) {
console.trace();
}
return function (/** @type {any} */ value, /** @type {boolean} */ mutation) {
if (arguments.length > 0) {
const new_value = mutation ? get(d) : runes && bindable ? proxy(value) : value;
@ -390,10 +422,12 @@ export function prop(props, key, flags, fallback) {
return value;
}
// special case — avoid recalculating the derived if
// we're in a teardown function and the prop
// was overridden locally
if (is_destroying_effect && overridden) {
// special case — avoid recalculating the derived if we're in a
// teardown function and the prop was overridden locally, or the
// component was already destroyed (this latter part is necessary
// because `bind:this` can read props after the component has
// been destroyed. TODO simplify `bind:this`
if ((is_destroying_effect && overridden) || (parent_effect.f & DESTROYED) !== 0) {
return d.v;
}

Loading…
Cancel
Save