diff --git a/packages/svelte/src/compiler/compile/render_dom/invalidate.js b/packages/svelte/src/compiler/compile/render_dom/invalidate.js index 83423e952b..3401e7aec7 100644 --- a/packages/svelte/src/compiler/compile/render_dom/invalidate.js +++ b/packages/svelte/src/compiler/compile/render_dom/invalidate.js @@ -38,7 +38,8 @@ export function invalidate(renderer, scope, node, names, main_execution_context * @param {import('estree').Expression} [node] */ function get_invalidated(variable, node) { - if (main_execution_context && !variable.subscribable && variable.name[0] !== '$') { + const is_props = !!variable.export_name; + if (main_execution_context && !is_props && !variable.subscribable && variable.name[0] !== '$') { return node; } return renderer_invalidate(renderer, variable.name, undefined, main_execution_context); @@ -61,8 +62,9 @@ export function invalidate(renderer, scope, node, names, main_execution_context return x`@set_store_value(${head.name.slice(1)}, ${node}, ${head.name}, ${extra_args})`; } + const is_props = !!head.export_name; let invalidate; - if (!main_execution_context) { + if (!main_execution_context || is_props) { const pass_value = extra_args.length > 0 || (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') || @@ -96,8 +98,9 @@ export function invalidate(renderer, scope, node, names, main_execution_context */ export function renderer_invalidate(renderer, name, value, main_execution_context = false) { const variable = renderer.component.var_lookup.get(name); + const is_props = variable && variable.export_name && !variable.module; if (variable && variable.subscribable && (variable.reassigned || variable.export_name)) { - if (main_execution_context) { + if (main_execution_context && !is_props) { return x`${`$$subscribe_${name}`}(${value || name})`; } else { const member = renderer.context_lookup.get(name); @@ -124,6 +127,9 @@ export function renderer_invalidate(renderer, name, value, main_execution_contex const member = renderer.context_lookup.get(name); return x`$$invalidate(${member.index}, ${value})`; } + } else if (main_execution_context && is_props) { + const member = renderer.context_lookup.get(name); + return x`$$invalidate(${member.index}, ${name})`; } if (main_execution_context) return; // if this is a reactive declaration, invalidate dependencies recursively diff --git a/packages/svelte/src/runtime/internal/Component.js b/packages/svelte/src/runtime/internal/Component.js index 5b38f7ffd8..5463a5c491 100644 --- a/packages/svelte/src/runtime/internal/Component.js +++ b/packages/svelte/src/runtime/internal/Component.js @@ -24,7 +24,8 @@ export function bind(component, name, callback) { const i = component.$$.props[name]; if (i !== undefined) { let dirty = false; - if (component.$$.bound[i]) dirty = true; + // special dirty flag for bind + if (component.$$.bound[i] === null) dirty = true; component.$$.bound[i] = callback; // first binding call, if child value is not yet dirty, skip to prevent unnecessary backflow callback(component.$$.ctx[i], /** skip_binding */ !dirty); @@ -127,10 +128,13 @@ export function init( $$.ctx = instance ? instance(component, options.props || {}, (i, ret, ...rest) => { const value = rest.length ? rest[0] : ret; + // `$$.bound[i] = null` as a special dirty flag to prevent unnecessary backflow, consumed in bind() + // only set at init phase during `instance()` call, and 1st `$$.update()` call before `ready` + if (!$$.ctx) $$.bound[i] = null; if ($$.ctx && not_equal($$.ctx[i], ($$.ctx[i] = value))) { - if (!$$.skip_bound && is_function($$.bound[i])) $$.bound[i](value); + if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value); if (ready) make_dirty(component, i); - else $$.bound[i] = true; // dirty flag consumed in bind() + else $$.bound[i] = null; } return ret; })