Skip to content

Commit 3330c3f

Browse files
authored
only add event listeners when a block is first mounted (#4860)
1 parent 24ef4e1 commit 3330c3f

File tree

31 files changed

+305
-132
lines changed

31 files changed

+305
-132
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Add `a11y-no-onchange` warning ([#4788](https://github.com/sveltejs/svelte/pull/4788))
1010
* Add `muted` binding for media elements ([#2998](https://github.com/sveltejs/svelte/issues/2998))
1111
* Fix let-less `<slot>` with context overflow ([#4624](https://github.com/sveltejs/svelte/issues/4624))
12+
* Fix `use:` actions being recreated when a keyed `{#each}` is reordered ([#4693](https://github.com/sveltejs/svelte/issues/4693))
1213

1314
## 3.22.3
1415

src/compiler/compile/render_dom/Block.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ export default class Block {
299299
${this.chunks.mount}
300300
}`;
301301
} else {
302-
properties.mount = x`function #mount(#target, #anchor, #remount) {
302+
properties.mount = x`function #mount(#target, #anchor) {
303303
${this.chunks.mount}
304304
}`;
305305
}
@@ -452,6 +452,9 @@ export default class Block {
452452

453453
render_listeners(chunk: string = '') {
454454
if (this.event_listeners.length > 0) {
455+
this.add_variable({ type: 'Identifier', name: '#mounted' });
456+
this.chunks.destroy.push(b`#mounted = false`);
457+
455458
const dispose: Identifier = {
456459
type: 'Identifier',
457460
name: `#dispose${chunk}`
@@ -462,8 +465,10 @@ export default class Block {
462465
if (this.event_listeners.length === 1) {
463466
this.chunks.mount.push(
464467
b`
465-
if (#remount) ${dispose}();
466-
${dispose} = ${this.event_listeners[0]};
468+
if (!#mounted) {
469+
${dispose} = ${this.event_listeners[0]};
470+
#mounted = true;
471+
}
467472
`
468473
);
469474

@@ -472,10 +477,12 @@ export default class Block {
472477
);
473478
} else {
474479
this.chunks.mount.push(b`
475-
if (#remount) @run_all(${dispose});
476-
${dispose} = [
477-
${this.event_listeners}
478-
];
480+
if (!#mounted) {
481+
${dispose} = [
482+
${this.event_listeners}
483+
];
484+
#mounted = true;
485+
}
479486
`);
480487

481488
this.chunks.destroy.push(

src/runtime/internal/keyed_each.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export function update_keyed_each(old_blocks, dirty, get_key, dynamic, ctx, list
5656

5757
function insert(block) {
5858
transition_in(block, 1);
59-
block.m(node, next, lookup.has(block.key));
59+
block.m(node, next);
6060
lookup.set(block.key, block);
6161
next = block.first;
6262
n--;

test/js/samples/action-custom-event-handler/expected.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,21 @@ import {
1414
function create_fragment(ctx) {
1515
let button;
1616
let foo_action;
17+
let mounted;
1718
let dispose;
1819

1920
return {
2021
c() {
2122
button = element("button");
2223
button.textContent = "foo";
2324
},
24-
m(target, anchor, remount) {
25+
m(target, anchor) {
2526
insert(target, button, anchor);
26-
if (remount) dispose();
27-
dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
27+
28+
if (!mounted) {
29+
dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
30+
mounted = true;
31+
}
2832
},
2933
p(ctx, [dirty]) {
3034
if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]);
@@ -33,6 +37,7 @@ function create_fragment(ctx) {
3337
o: noop,
3438
d(detaching) {
3539
if (detaching) detach(button);
40+
mounted = false;
3641
dispose();
3742
}
3843
};

test/js/samples/action/expected.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
function create_fragment(ctx) {
1515
let a;
1616
let link_action;
17+
let mounted;
1718
let dispose;
1819

1920
return {
@@ -22,16 +23,20 @@ function create_fragment(ctx) {
2223
a.textContent = "Test";
2324
attr(a, "href", "#");
2425
},
25-
m(target, anchor, remount) {
26+
m(target, anchor) {
2627
insert(target, a, anchor);
27-
if (remount) dispose();
28-
dispose = action_destroyer(link_action = link.call(null, a));
28+
29+
if (!mounted) {
30+
dispose = action_destroyer(link_action = link.call(null, a));
31+
mounted = true;
32+
}
2933
},
3034
p: noop,
3135
i: noop,
3236
o: noop,
3337
d(detaching) {
3438
if (detaching) detach(a);
39+
mounted = false;
3540
dispose();
3641
}
3742
};

test/js/samples/bind-online/expected.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,27 @@ import {
1010
} from "svelte/internal";
1111

1212
function create_fragment(ctx) {
13+
let mounted;
1314
let dispose;
1415
add_render_callback(/*onlinestatuschanged*/ ctx[1]);
1516

1617
return {
1718
c: noop,
18-
m(target, anchor, remount) {
19-
if (remount) run_all(dispose);
20-
21-
dispose = [
22-
listen(window, "online", /*onlinestatuschanged*/ ctx[1]),
23-
listen(window, "offline", /*onlinestatuschanged*/ ctx[1])
24-
];
19+
m(target, anchor) {
20+
if (!mounted) {
21+
dispose = [
22+
listen(window, "online", /*onlinestatuschanged*/ ctx[1]),
23+
listen(window, "offline", /*onlinestatuschanged*/ ctx[1])
24+
];
25+
26+
mounted = true;
27+
}
2528
},
2629
p: noop,
2730
i: noop,
2831
o: noop,
2932
d(detaching) {
33+
mounted = false;
3034
run_all(dispose);
3135
}
3236
};

test/js/samples/bind-open/expected.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212

1313
function create_fragment(ctx) {
1414
let details;
15+
let mounted;
1516
let dispose;
1617

1718
return {
@@ -21,11 +22,14 @@ function create_fragment(ctx) {
2122
details.innerHTML = `<summary>summary</summary>content
2223
`;
2324
},
24-
m(target, anchor, remount) {
25+
m(target, anchor) {
2526
insert(target, details, anchor);
2627
details.open = /*open*/ ctx[0];
27-
if (remount) dispose();
28-
dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]);
28+
29+
if (!mounted) {
30+
dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]);
31+
mounted = true;
32+
}
2933
},
3034
p(ctx, [dirty]) {
3135
if (dirty & /*open*/ 1) {
@@ -36,6 +40,7 @@ function create_fragment(ctx) {
3640
o: noop,
3741
d(detaching) {
3842
if (detaching) detach(details);
43+
mounted = false;
3944
dispose();
4045
}
4146
};

test/js/samples/bindings-readonly-order/expected.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function create_fragment(ctx) {
1717
let input0;
1818
let t;
1919
let input1;
20+
let mounted;
2021
let dispose;
2122

2223
return {
@@ -27,16 +28,19 @@ function create_fragment(ctx) {
2728
attr(input0, "type", "file");
2829
attr(input1, "type", "file");
2930
},
30-
m(target, anchor, remount) {
31+
m(target, anchor) {
3132
insert(target, input0, anchor);
3233
insert(target, t, anchor);
3334
insert(target, input1, anchor);
34-
if (remount) run_all(dispose);
3535

36-
dispose = [
37-
listen(input0, "change", /*input0_change_handler*/ ctx[1]),
38-
listen(input1, "change", /*input1_change_handler*/ ctx[2])
39-
];
36+
if (!mounted) {
37+
dispose = [
38+
listen(input0, "change", /*input0_change_handler*/ ctx[1]),
39+
listen(input1, "change", /*input1_change_handler*/ ctx[2])
40+
];
41+
42+
mounted = true;
43+
}
4044
},
4145
p: noop,
4246
i: noop,
@@ -45,6 +49,7 @@ function create_fragment(ctx) {
4549
if (detaching) detach(input0);
4650
if (detaching) detach(t);
4751
if (detaching) detach(input1);
52+
mounted = false;
4853
run_all(dispose);
4954
}
5055
};

test/js/samples/capture-inject-dev-only/expected.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function create_fragment(ctx) {
2020
let t0;
2121
let t1;
2222
let input;
23+
let mounted;
2324
let dispose;
2425

2526
return {
@@ -29,14 +30,17 @@ function create_fragment(ctx) {
2930
t1 = space();
3031
input = element("input");
3132
},
32-
m(target, anchor, remount) {
33+
m(target, anchor) {
3334
insert(target, p, anchor);
3435
append(p, t0);
3536
insert(target, t1, anchor);
3637
insert(target, input, anchor);
3738
set_input_value(input, /*foo*/ ctx[0]);
38-
if (remount) dispose();
39-
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
39+
40+
if (!mounted) {
41+
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
42+
mounted = true;
43+
}
4044
},
4145
p(ctx, [dirty]) {
4246
if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]);
@@ -51,6 +55,7 @@ function create_fragment(ctx) {
5155
if (detaching) detach(p);
5256
if (detaching) detach(t1);
5357
if (detaching) detach(input);
58+
mounted = false;
5459
dispose();
5560
}
5661
};

test/js/samples/component-static-var/expected.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ function create_fragment(ctx) {
2424
let t1;
2525
let input;
2626
let current;
27+
let mounted;
2728
let dispose;
2829
const foo = new Foo({ props: { x: y } });
2930
const bar = new Bar({ props: { x: /*z*/ ctx[0] } });
@@ -36,16 +37,19 @@ function create_fragment(ctx) {
3637
t1 = space();
3738
input = element("input");
3839
},
39-
m(target, anchor, remount) {
40+
m(target, anchor) {
4041
mount_component(foo, target, anchor);
4142
insert(target, t0, anchor);
4243
mount_component(bar, target, anchor);
4344
insert(target, t1, anchor);
4445
insert(target, input, anchor);
4546
set_input_value(input, /*z*/ ctx[0]);
4647
current = true;
47-
if (remount) dispose();
48-
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
48+
49+
if (!mounted) {
50+
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
51+
mounted = true;
52+
}
4953
},
5054
p(ctx, [dirty]) {
5155
const bar_changes = {};
@@ -73,6 +77,7 @@ function create_fragment(ctx) {
7377
destroy_component(bar, detaching);
7478
if (detaching) detach(t1);
7579
if (detaching) detach(input);
80+
mounted = false;
7681
dispose();
7782
}
7883
};

0 commit comments

Comments
 (0)