Skip to content

Commit c8ab9e6

Browse files
committed
fix
1 parent 05636d3 commit c8ab9e6

File tree

1 file changed

+54
-20
lines changed
  • packages/svelte/src/internal/client/reactivity

1 file changed

+54
-20
lines changed

packages/svelte/src/internal/client/reactivity/props.js

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @import { ComponentContext } from '#client' */
2-
/** @import { Derived, Source } from './types.js' */
2+
/** @import { Derived, Effect, Source } from './types.js' */
33
import { DEV } from 'esm-env';
44
import {
55
PROPS_IS_BINDABLE,
@@ -12,9 +12,15 @@ import {
1212
import { get_descriptor, is_function } from '../../shared/utils.js';
1313
import { set, source, update } from './sources.js';
1414
import { derived, derived_safe_equal } from './deriveds.js';
15-
import { get, is_destroying_effect, untrack } from '../runtime.js';
15+
import {
16+
active_effect,
17+
get,
18+
is_destroying_effect,
19+
set_active_effect,
20+
untrack
21+
} from '../runtime.js';
1622
import * as e from '../errors.js';
17-
import { LEGACY_PROPS, STATE_SYMBOL } from '#client/constants';
23+
import { DESTROYED, LEGACY_PROPS, STATE_SYMBOL } from '#client/constants';
1824
import { proxy } from '../proxy.js';
1925
import { capture_store_binding } from './store.js';
2026
import { legacy_mode_flag } from '../../flags/index.js';
@@ -94,7 +100,7 @@ export function rest_props(props, exclude, name) {
94100

95101
/**
96102
* The proxy handler for legacy $$restProps and $$props
97-
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number> }>}}
103+
* @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number>, parent_effect: Effect }>}}
98104
*/
99105
const legacy_rest_props_handler = {
100106
get(target, key) {
@@ -104,17 +110,25 @@ const legacy_rest_props_handler = {
104110
},
105111
set(target, key, value) {
106112
if (!(key in target.special)) {
107-
// Handle props that can temporarily get out of sync with the parent
108-
/** @type {Record<string, (v?: unknown) => unknown>} */
109-
target.special[key] = prop(
110-
{
111-
get [key]() {
112-
return target.props[key];
113-
}
114-
},
115-
/** @type {string} */ (key),
116-
PROPS_IS_UPDATED
117-
);
113+
var previous_effect = active_effect;
114+
115+
try {
116+
set_active_effect(target.parent_effect);
117+
118+
// Handle props that can temporarily get out of sync with the parent
119+
/** @type {Record<string, (v?: unknown) => unknown>} */
120+
target.special[key] = prop(
121+
{
122+
get [key]() {
123+
return target.props[key];
124+
}
125+
},
126+
/** @type {string} */ (key),
127+
PROPS_IS_UPDATED
128+
);
129+
} finally {
130+
set_active_effect(previous_effect);
131+
}
118132
}
119133

120134
target.special[key](value);
@@ -153,7 +167,19 @@ const legacy_rest_props_handler = {
153167
* @returns {Record<string, unknown>}
154168
*/
155169
export function legacy_rest_props(props, exclude) {
156-
return new Proxy({ props, exclude, special: {}, version: source(0) }, legacy_rest_props_handler);
170+
return new Proxy(
171+
{
172+
props,
173+
exclude,
174+
special: {},
175+
version: source(0),
176+
// TODO this is only necessary because we need to track component
177+
// destruction inside `prop`, because of `bind:this`, but it
178+
// seems likely that we can simplify `bind:this` instead
179+
parent_effect: /** @type {Effect} */ (active_effect)
180+
},
181+
legacy_rest_props_handler
182+
);
157183
}
158184

159185
/**
@@ -376,6 +402,12 @@ export function prop(props, key, flags, fallback) {
376402
// Capture the initial value if it's bindable
377403
if (bindable) get(d);
378404

405+
var parent_effect = /** @type {Effect} */ (active_effect);
406+
407+
if (!parent_effect) {
408+
console.trace();
409+
}
410+
379411
return function (/** @type {any} */ value, /** @type {boolean} */ mutation) {
380412
if (arguments.length > 0) {
381413
const new_value = mutation ? get(d) : runes && bindable ? proxy(value) : value;
@@ -390,10 +422,12 @@ export function prop(props, key, flags, fallback) {
390422
return value;
391423
}
392424

393-
// special case — avoid recalculating the derived if
394-
// we're in a teardown function and the prop
395-
// was overridden locally
396-
if (is_destroying_effect && overridden) {
425+
// special case — avoid recalculating the derived if we're in a
426+
// teardown function and the prop was overridden locally, or the
427+
// component was already destroyed (this latter part is necessary
428+
// because `bind:this` can read props after the component has
429+
// been destroyed. TODO simplify `bind:this`
430+
if ((is_destroying_effect && overridden) || (parent_effect.f & DESTROYED) !== 0) {
397431
return d.v;
398432
}
399433

0 commit comments

Comments
 (0)