Skip to content

Commit 93443f9

Browse files
authored
fix: only re-run directly applied attachment if it changed (#15962)
* fix: only re-run directly applied attachment if it changed * add note * one down * fix * Revert "one down" This reverts commit 9f6c4cf.
1 parent c66a439 commit 93443f9

File tree

4 files changed

+60
-6
lines changed

4 files changed

+60
-6
lines changed

.changeset/slimy-drinks-divide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: only re-run directly applied attachment if it changed
Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
1-
import { effect } from '../../reactivity/effects.js';
1+
/** @import { Effect } from '#client' */
2+
import { block, branch, effect, destroy_effect } from '../../reactivity/effects.js';
3+
4+
// TODO in 6.0 or 7.0, when we remove legacy mode, we can simplify this by
5+
// getting rid of the block/branch stuff and just letting the effect rip.
6+
// see https://github.com/sveltejs/svelte/pull/15962
27

38
/**
49
* @param {Element} node
510
* @param {() => (node: Element) => void} get_fn
611
*/
712
export function attach(node, get_fn) {
8-
effect(() => {
9-
const fn = get_fn();
13+
/** @type {false | undefined | ((node: Element) => void)} */
14+
var fn = undefined;
15+
16+
/** @type {Effect | null} */
17+
var e;
18+
19+
block(() => {
20+
if (fn !== (fn = get_fn())) {
21+
if (e) {
22+
destroy_effect(e);
23+
e = null;
24+
}
1025

11-
// we use `&&` rather than `?.` so that things like
12-
// `{@attach DEV && something_dev_only()}` work
13-
return fn && fn(node);
26+
if (fn) {
27+
e = branch(() => {
28+
effect(() => /** @type {(node: Element) => void} */ (fn)(node));
29+
});
30+
}
31+
}
1432
});
1533
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
test({ assert, target, logs }) {
6+
assert.deepEqual(logs, ['up']);
7+
8+
const button = target.querySelector('button');
9+
10+
flushSync(() => button?.click());
11+
assert.deepEqual(logs, ['up']);
12+
13+
flushSync(() => button?.click());
14+
assert.deepEqual(logs, ['up', 'down']);
15+
}
16+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script>
2+
let state = {
3+
count: 0,
4+
attachment(){
5+
console.log('up');
6+
return () => console.log('down');
7+
}
8+
};
9+
</script>
10+
11+
<button onclick={() => state.count++}>{state.count}</button>
12+
13+
{#if state.count < 2}
14+
<div {@attach state.attachment}></div>
15+
{/if}

0 commit comments

Comments
 (0)