Closed
Description
Description of the bug
- When attaching "use" directives inside a keyed block, they are called again (without being destroyed) if the elements of the block are reordered.
To Reproduce
- This REPL reproduces the issue: https://svelte.dev/repl/4b0807cd0596423b94e31a24bde9497a?version=3.20.1
Expected behavior
- Directives should be called only once when the component is mounted.
- Alternatively, if the element is remounted, "destroy" should be called beforehand (e.g. to free previously created resources).
Information about the Svelte project:
- Svelte version: 3.20.1 (bundled with Rollup)
- Browser: (latest) Chrome on MacOS
Severity
- Moderate to serious, since the application we are building is relying heavily on use-directives to leverage modularity. We noticed the issue when event listeners were mounted multiple times (leading to a memory leak as well as unexpected behavior and inconsistent internal state).
Additional context
- The issue only happens with keyed each blocks.
Previous analysis
- Here is where things break:
/* src/ListItem.svelte generated by Svelte v3.20.1 */
function create_fragment(ctx) {
let div;
let t;
let directive_action;
let dispose;
return {
c() {
div = element("div");
t = text(/*id*/ ctx[0]);
},
m(target, anchor, remount) {
insert(target, div, anchor);
append(div, t);
if (remount) dispose(); // <-- remount is undefined
dispose = action_destroyer(directive_action = directive.call(null, div, { id: /*id*/ ctx[0] }));
},
It seems that remounting was considered, but the information (that the current operation is indeed a remount) gets lost due to an additional block in between. It's a bit hard to describe verbally. So here are the relevant parts of a debugger session (from the same app as in the example REPL):