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 9f6c4cf848.
pull/15959/head
Rich Harris 4 months ago committed by GitHub
parent c66a43940a
commit 93443f9316
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: only re-run directly applied attachment if it changed

@ -1,15 +1,33 @@
import { effect } from '../../reactivity/effects.js';
/** @import { Effect } from '#client' */
import { block, branch, effect, destroy_effect } from '../../reactivity/effects.js';
// TODO in 6.0 or 7.0, when we remove legacy mode, we can simplify this by
// getting rid of the block/branch stuff and just letting the effect rip.
// see https://github.com/sveltejs/svelte/pull/15962
/**
* @param {Element} node
* @param {() => (node: Element) => void} get_fn
*/
export function attach(node, get_fn) {
effect(() => {
const fn = get_fn();
/** @type {false | undefined | ((node: Element) => void)} */
var fn = undefined;
/** @type {Effect | null} */
var e;
block(() => {
if (fn !== (fn = get_fn())) {
if (e) {
destroy_effect(e);
e = null;
}
// we use `&&` rather than `?.` so that things like
// `{@attach DEV && something_dev_only()}` work
return fn && fn(node);
if (fn) {
e = branch(() => {
effect(() => /** @type {(node: Element) => void} */ (fn)(node));
});
}
}
});
}

@ -0,0 +1,16 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
test({ assert, target, logs }) {
assert.deepEqual(logs, ['up']);
const button = target.querySelector('button');
flushSync(() => button?.click());
assert.deepEqual(logs, ['up']);
flushSync(() => button?.click());
assert.deepEqual(logs, ['up', 'down']);
}
});

@ -0,0 +1,15 @@
<script>
let state = {
count: 0,
attachment(){
console.log('up');
return () => console.log('down');
}
};
</script>
<button onclick={() => state.count++}>{state.count}</button>
{#if state.count < 2}
<div {@attach state.attachment}></div>
{/if}
Loading…
Cancel
Save