fix: flush remaining `afterUpdate` before `destroy` (#7516)

fixes #7476
pull/8311/head
Yuichiro Yamashita 2 years ago committed by GitHub
parent 57d869d028
commit a0cedf8d82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,4 @@
import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler';
import { add_render_callback, flush, flush_render_callbacks, schedule_update, dirty_components } from './scheduler';
import { current_component, set_current_component } from './lifecycle';
import { blank_object, is_empty, is_function, run, run_all, noop } from './utils';
import { children, detach, start_hydrating, end_hydrating } from './dom';
@ -51,6 +51,8 @@ export function mount_component(component, target, anchor, customElement) {
export function destroy_component(component, detaching) {
const $$ = component.$$;
if ($$.fragment !== null) {
flush_render_callbacks($$.after_update);
run_all($$.on_destroy);
$$.fragment && $$.fragment.d(detaching);

@ -5,7 +5,7 @@ export const dirty_components = [];
export const intros = { enabled: false };
export const binding_callbacks = [];
const render_callbacks = [];
let render_callbacks = [];
const flush_callbacks = [];
const resolved_promise = Promise.resolve();
@ -122,3 +122,14 @@ function update($$) {
$$.after_update.forEach(add_render_callback);
}
}
/**
* Useful for example to execute remaining `afterUpdate` callbacks before executing `destroy`.
*/
export function flush_render_callbacks(fns: Function[]): void {
const filtered = [];
const targets = [];
render_callbacks.forEach((c) => fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c));
targets.forEach((c) => c());
render_callbacks = filtered;
}

@ -0,0 +1,27 @@
<script>
import { afterUpdate, onDestroy } from "svelte";
export let id;
export let items;
let item = $items[id];
let selected = true;
function onClick() {
selected = !selected;
items.set({});
}
onDestroy(() => {
console.log("onDestroy");
});
afterUpdate(() => {
console.log("afterUpdate");
});
</script>
<button on:click="{onClick}">Click Me</button>
{#if selected}
<div>{item.id}</div>
{/if}

@ -0,0 +1,16 @@
export default {
html: `
<button>Click Me</button>
<div>1</div>
`,
async test({ assert, target, window }) {
const button = target.querySelector('button');
const event = new window.MouseEvent('click');
const messages = [];
const log = console.log;
console.log = msg => messages.push(msg);
await button.dispatchEvent(event);
console.log = log;
assert.deepEqual(messages, ['afterUpdate', 'onDestroy']);
}
};

@ -0,0 +1,10 @@
<script>
import { writable } from 'svelte/store';
import Component from "./Component.svelte";
let items = writable({ 1: { id: 1 } });
</script>
{#each Object.values($items) as item (item.id)}
<Component id="{item.id}" {items} />
{/each}
Loading…
Cancel
Save