Fix: beforeUpdate called twice with bound reference

Fixes: https://github.com/sveltejs/svelte/issues/6016
Fixes: https://github.com/sveltejs/svelte/issues/3290
pull/6858/head
raivaibhav 5 years ago committed by vaibhav rai
parent 2c8e77bf90
commit 7206a24919

@ -33,6 +33,8 @@ export function add_flush_callback(fn) {
let flushing = false; let flushing = false;
const seen_callbacks = new Set(); const seen_callbacks = new Set();
let dirty_binding_component_map = new Map();
export function flush() { export function flush() {
if (flushing) return; if (flushing) return;
flushing = true; flushing = true;
@ -43,14 +45,19 @@ export function flush() {
for (let i = 0; i < dirty_components.length; i += 1) { for (let i = 0; i < dirty_components.length; i += 1) {
const component = dirty_components[i]; const component = dirty_components[i];
set_current_component(component); set_current_component(component);
update(component.$$); const is_dirty_from_binding = dirty_binding_component_map.has(component.constructor.name);
update(component.$$, is_dirty_from_binding);
} }
dirty_binding_component_map = new Map();
set_current_component(null); set_current_component(null);
dirty_components.length = 0; dirty_components.length = 0;
while (binding_callbacks.length) binding_callbacks.pop()(); while (binding_callbacks.length) {
binding_callbacks.pop()();
}
dirty_components.forEach((i) =>
dirty_binding_component_map.set(i.constructor.name, i));
// then, once components are updated, call // then, once components are updated, call
// afterUpdate functions. This may cause // afterUpdate functions. This may cause
// subsequent updates... // subsequent updates...
@ -77,14 +84,14 @@ export function flush() {
seen_callbacks.clear(); seen_callbacks.clear();
} }
function update($$) { function update($$, is_dirty_from_binding) {
if ($$.fragment !== null) { if ($$.fragment !== null) {
$$.update(); $$.update();
run_all($$.before_update); if (!is_dirty_from_binding) run_all($$.before_update);
const dirty = $$.dirty; const dirty = $$.dirty;
$$.dirty = [-1]; $$.dirty = [-1];
$$.fragment && $$.fragment.p($$.ctx, dirty); $$.fragment && $$.fragment.p($$.ctx, dirty);
// if (!is_dirty_from_binding) run_all($$.after_update);
$$.after_update.forEach(add_render_callback); $$.after_update.forEach(add_render_callback);
} }
} }

@ -0,0 +1,30 @@
<script>
import { onMount, beforeUpdate, afterUpdate } from 'svelte';
import order from './order.js';
let i;
export let index;
export let id;
export let name;
function logRender () {
order.push(`${index}: render`);
return index;
}
beforeUpdate(() => {
order.push(`${index}: beforeUpdate`);
});
afterUpdate(() => {
order.push(`${index}: afterUpdate`);
});
onMount(() => {
order.push(`${index}: onMount`);
});
</script>
<li bind:this={i}>
{logRender()}
</li>

@ -0,0 +1,49 @@
import order from './order.js';
export default {
skip_if_ssr: true,
before_test() {
order.length = 0;
},
test({ assert, compileOptions }) {
if (compileOptions.hydratable) {
assert.deepEqual(order, [
'0: beforeUpdate',
'0: render',
'1: beforeUpdate',
'1: render',
'2: beforeUpdate',
'2: render',
'3: beforeUpdate',
'3: render',
'1: onMount',
'1: afterUpdate',
'2: onMount',
'2: afterUpdate',
'3: onMount',
'3: afterUpdate',
'0: onMount',
'0: afterUpdate'
]);
} else {
assert.deepEqual(order, [
'0: beforeUpdate',
'0: render',
'1: beforeUpdate',
'2: beforeUpdate',
'3: beforeUpdate',
'1: render',
'2: render',
'3: render',
'1: onMount',
'1: afterUpdate',
'2: onMount',
'2: afterUpdate',
'3: onMount',
'3: afterUpdate',
'0: onMount',
'0: afterUpdate'
]);
}
}
};

@ -0,0 +1,34 @@
<script>
import { onMount, beforeUpdate, afterUpdate } from 'svelte';
import order from './order.js';
import Item from './Item.svelte';
const parentIndex = 0;
let ul;
let ulW;
function logRender () {
order.push(`${parentIndex}: render`);
return parentIndex;
}
beforeUpdate(() => {
order.push(`${parentIndex}: beforeUpdate`);
});
afterUpdate(() => {
order.push(`${parentIndex}: afterUpdate`);
});
onMount(() => {
order.push(`${parentIndex}: onMount`);
})
</script>
{logRender()}
<ul bind:this={ul} bind:clientWidth={ulW}>
{#each [1,2,3] as index}
<Item {index} />
{/each}
</ul>
Loading…
Cancel
Save