fix: only destroy snippets when they have changed (#11267)

* fix: only destroy snippets when they have changed

* tidy up

* changeset

* oops

* tidy up
pull/11260/head
Rich Harris 1 year ago committed by GitHub
parent 5ef1fdf7cc
commit 47ba488cf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: only destroy snippets when they have changed

@ -20,15 +20,17 @@ export function if_block(
elseif = false
) {
/** @type {import('#client').Effect | null} */
let consequent_effect = null;
var consequent_effect = null;
/** @type {import('#client').Effect | null} */
let alternate_effect = null;
var alternate_effect = null;
/** @type {boolean | null} */
let condition = null;
var condition = null;
const effect = block(() => {
var flags = elseif ? EFFECT_TRANSPARENT : 0;
block(() => {
if (condition === (condition = !!get_condition())) return;
/** 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(
// continue in hydration mode
set_hydrating(true);
}
});
if (elseif) {
effect.f |= EFFECT_TRANSPARENT;
}
}, flags);
}

@ -1,5 +1,5 @@
import { EFFECT_TRANSPARENT } from '../../constants.js';
import { branch, render_effect } from '../../reactivity/effects.js';
import { branch, block, destroy_effect } from '../../reactivity/effects.js';
/**
* @template {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} SnippetFn
@ -12,13 +12,19 @@ export function snippet(get_snippet, node, ...args) {
/** @type {SnippetFn | null | undefined} */
var snippet;
var effect = render_effect(() => {
/** @type {import('#client').Effect | null} */
var snippet_effect;
block(() => {
if (snippet === (snippet = get_snippet())) return;
if (snippet) {
branch(() => /** @type {SnippetFn} */ (snippet)(node, ...args));
if (snippet_effect) {
destroy_effect(snippet_effect);
snippet_effect = null;
}
});
effect.f |= EFFECT_TRANSPARENT;
if (snippet) {
snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(node, ...args));
}
}, EFFECT_TRANSPARENT);
}

@ -7,7 +7,7 @@ import { should_intro } from '../../render.js';
import { is_function } from '../../utils.js';
import { current_each_item } from '../blocks/each.js';
import { TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT } from '../../../../constants.js';
import { BLOCK_EFFECT, EFFECT_RAN } from '../../constants.js';
import { BLOCK_EFFECT, EFFECT_RAN, EFFECT_TRANSPARENT } from '../../constants.js';
/**
* @template T
@ -241,18 +241,26 @@ export function transition(flags, element, get_fn, get_params) {
(e.transitions ??= []).push(transition);
// if this is a local transition, we only want to run it if the parent (block) effect's
// parent (branch) effect is where the state change happened. we can determine that by
// looking at whether the branch effect is currently initializing
// if this is a local transition, we only want to run it if the parent (branch) effect's
// parent (block) effect is where the state change happened. we can determine that by
// looking at whether the block effect is currently initializing
if (is_intro && should_intro) {
var parent = /** @type {import('#client').Effect} */ (e.parent);
let run = is_global;
// e.g snippets are implemented as render effects — keep going until we find the parent block
while ((parent.f & BLOCK_EFFECT) === 0 && parent.parent) {
parent = parent.parent;
if (!run) {
var block = /** @type {import('#client').Effect | null} */ (e.parent);
// skip over transparent blocks (e.g. snippets, else-if blocks)
while (block && (block.f & EFFECT_TRANSPARENT) !== 0) {
while ((block = block.parent)) {
if ((block.f & BLOCK_EFFECT) !== 0) break;
}
}
run = !block || (block.f & EFFECT_RAN) !== 0;
}
if (is_global || (parent.f & EFFECT_RAN) !== 0) {
if (run) {
effect(() => {
untrack(() => transition.in());
});

@ -230,9 +230,12 @@ export function render_effect(fn) {
return create_effect(RENDER_EFFECT, fn, true);
}
/** @param {(() => void)} fn */
export function block(fn) {
return create_effect(RENDER_EFFECT | BLOCK_EFFECT, fn, true);
/**
* @param {(() => void)} fn
* @param {number} flags
*/
export function block(fn, flags = 0) {
return create_effect(RENDER_EFFECT | BLOCK_EFFECT | flags, fn, true);
}
/** @param {(() => void)} fn */

Loading…
Cancel
Save