Skip to content

Commit 47ba488

Browse files
authored
fix: only destroy snippets when they have changed (#11267)
* fix: only destroy snippets when they have changed * tidy up * changeset * oops * tidy up
1 parent 5ef1fdf commit 47ba488

File tree

5 files changed

+47
-27
lines changed

5 files changed

+47
-27
lines changed

.changeset/shiny-mayflies-clean.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 destroy snippets when they have changed

packages/svelte/src/internal/client/dom/blocks/if.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ export function if_block(
2020
elseif = false
2121
) {
2222
/** @type {import('#client').Effect | null} */
23-
let consequent_effect = null;
23+
var consequent_effect = null;
2424

2525
/** @type {import('#client').Effect | null} */
26-
let alternate_effect = null;
26+
var alternate_effect = null;
2727

2828
/** @type {boolean | null} */
29-
let condition = null;
29+
var condition = null;
3030

31-
const effect = block(() => {
31+
var flags = elseif ? EFFECT_TRANSPARENT : 0;
32+
33+
block(() => {
3234
if (condition === (condition = !!get_condition())) return;
3335

3436
/** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
@@ -76,9 +78,5 @@ export function if_block(
7678
// continue in hydration mode
7779
set_hydrating(true);
7880
}
79-
});
80-
81-
if (elseif) {
82-
effect.f |= EFFECT_TRANSPARENT;
83-
}
81+
}, flags);
8482
}
Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { EFFECT_TRANSPARENT } from '../../constants.js';
2-
import { branch, render_effect } from '../../reactivity/effects.js';
2+
import { branch, block, destroy_effect } from '../../reactivity/effects.js';
33

44
/**
55
* @template {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} SnippetFn
@@ -12,13 +12,19 @@ export function snippet(get_snippet, node, ...args) {
1212
/** @type {SnippetFn | null | undefined} */
1313
var snippet;
1414

15-
var effect = render_effect(() => {
15+
/** @type {import('#client').Effect | null} */
16+
var snippet_effect;
17+
18+
block(() => {
1619
if (snippet === (snippet = get_snippet())) return;
1720

18-
if (snippet) {
19-
branch(() => /** @type {SnippetFn} */ (snippet)(node, ...args));
21+
if (snippet_effect) {
22+
destroy_effect(snippet_effect);
23+
snippet_effect = null;
2024
}
21-
});
2225

23-
effect.f |= EFFECT_TRANSPARENT;
26+
if (snippet) {
27+
snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(node, ...args));
28+
}
29+
}, EFFECT_TRANSPARENT);
2430
}

packages/svelte/src/internal/client/dom/elements/transitions.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { should_intro } from '../../render.js';
77
import { is_function } from '../../utils.js';
88
import { current_each_item } from '../blocks/each.js';
99
import { TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT } from '../../../../constants.js';
10-
import { BLOCK_EFFECT, EFFECT_RAN } from '../../constants.js';
10+
import { BLOCK_EFFECT, EFFECT_RAN, EFFECT_TRANSPARENT } from '../../constants.js';
1111

1212
/**
1313
* @template T
@@ -241,18 +241,26 @@ export function transition(flags, element, get_fn, get_params) {
241241

242242
(e.transitions ??= []).push(transition);
243243

244-
// if this is a local transition, we only want to run it if the parent (block) effect's
245-
// parent (branch) effect is where the state change happened. we can determine that by
246-
// looking at whether the branch effect is currently initializing
244+
// if this is a local transition, we only want to run it if the parent (branch) effect's
245+
// parent (block) effect is where the state change happened. we can determine that by
246+
// looking at whether the block effect is currently initializing
247247
if (is_intro && should_intro) {
248-
var parent = /** @type {import('#client').Effect} */ (e.parent);
248+
let run = is_global;
249249

250-
// e.g snippets are implemented as render effects — keep going until we find the parent block
251-
while ((parent.f & BLOCK_EFFECT) === 0 && parent.parent) {
252-
parent = parent.parent;
250+
if (!run) {
251+
var block = /** @type {import('#client').Effect | null} */ (e.parent);
252+
253+
// skip over transparent blocks (e.g. snippets, else-if blocks)
254+
while (block && (block.f & EFFECT_TRANSPARENT) !== 0) {
255+
while ((block = block.parent)) {
256+
if ((block.f & BLOCK_EFFECT) !== 0) break;
257+
}
258+
}
259+
260+
run = !block || (block.f & EFFECT_RAN) !== 0;
253261
}
254262

255-
if (is_global || (parent.f & EFFECT_RAN) !== 0) {
263+
if (run) {
256264
effect(() => {
257265
untrack(() => transition.in());
258266
});

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,9 +230,12 @@ export function render_effect(fn) {
230230
return create_effect(RENDER_EFFECT, fn, true);
231231
}
232232

233-
/** @param {(() => void)} fn */
234-
export function block(fn) {
235-
return create_effect(RENDER_EFFECT | BLOCK_EFFECT, fn, true);
233+
/**
234+
* @param {(() => void)} fn
235+
* @param {number} flags
236+
*/
237+
export function block(fn, flags = 0) {
238+
return create_effect(RENDER_EFFECT | BLOCK_EFFECT | flags, fn, true);
236239
}
237240

238241
/** @param {(() => void)} fn */

0 commit comments

Comments
 (0)