Fix issue with multiple enrichments before components mount without affecting other components

This commit is contained in:
Andrew Kingston 2022-01-25 11:22:26 +00:00
parent bca6f34959
commit 542dc6db2f
1 changed files with 43 additions and 44 deletions

View File

@ -118,9 +118,6 @@
// Build up the final settings object to be passed to the component // Build up the final settings object to be passed to the component
$: cacheSettings(enrichedSettings, nestedSettings, conditionalSettings) $: cacheSettings(enrichedSettings, nestedSettings, conditionalSettings)
// Render key is used to determine when components need to fully remount
$: renderKey = getRenderKey(id, editing)
// Update component context // Update component context
$: componentStore.set({ $: componentStore.set({
id, id,
@ -276,8 +273,7 @@
// reactive statements as much as possible. // reactive statements as much as possible.
const cacheSettings = (enriched, nested, conditional) => { const cacheSettings = (enriched, nested, conditional) => {
const allSettings = { ...enriched, ...nested, ...conditional } const allSettings = { ...enriched, ...nested, ...conditional }
const mounted = ref?.$$set != null if (!cachedSettings) {
if (!cachedSettings || !mounted) {
cachedSettings = { ...allSettings } cachedSettings = { ...allSettings }
initialSettings = cachedSettings initialSettings = cachedSettings
} else { } else {
@ -290,51 +286,54 @@
// setting it on initialSettings directly, we avoid a double render. // setting it on initialSettings directly, we avoid a double render.
cachedSettings[key] = allSettings[key] cachedSettings[key] = allSettings[key]
// Programmatically set the prop to avoid svelte reactive statements if (ref?.$$set) {
// firing inside components. This circumvents the problems caused by // Programmatically set the prop to avoid svelte reactive statements
// spreading a props object. // firing inside components. This circumvents the problems caused by
ref.$$set({ [key]: allSettings[key] }) // spreading a props object.
ref.$$set({ [key]: allSettings[key] })
} else {
// Sometimes enrichment can occur multiple times before the
// component has mounted and been assigned a ref.
// In these cases, for some reason we need to update the
// initial settings object, even though it is equivalent by
// reference to cached settings. This solves the problem of multiple
// initial enrichments, while also not causing wasted renders for
// any components not affected by this issue.
initialSettings[key] = allSettings[key]
}
} }
}) })
} }
} }
// Generates a key used to determine when components need to fully remount.
// Currently only toggling editing requires remounting.
const getRenderKey = (id, editing) => {
return Helpers.hashString(`${id}-${editing}`)
}
</script> </script>
{#key renderKey} {#if constructor && initialSettings && (visible || inSelectedPath)}
{#if constructor && initialSettings && (visible || inSelectedPath)} <!-- The ID is used as a class because getElementsByClassName is O(1) -->
<!-- The ID is used as a class because getElementsByClassName is O(1) --> <!-- and the performance matters for the selection indicators -->
<!-- and the performance matters for the selection indicators --> <div
<div class={`component ${id}`}
class={`component ${id}`} class:draggable
class:draggable class:droppable
class:droppable class:empty
class:empty class:interactive
class:interactive class:editing
class:editing class:block={isBlock}
class:block={isBlock} data-id={id}
data-id={id} data-name={name}
data-name={name} >
> <svelte:component this={constructor} bind:this={ref} {...initialSettings}>
<svelte:component this={constructor} bind:this={ref} {...initialSettings}> {#if children.length}
{#if children.length} {#each children as child (child._id)}
{#each children as child (child._id)} <svelte:self instance={child} />
<svelte:self instance={child} /> {/each}
{/each} {:else if emptyState}
{:else if emptyState} <Placeholder />
<Placeholder /> {:else if isBlock}
{:else if isBlock} <slot />
<slot /> {/if}
{/if} </svelte:component>
</svelte:component> </div>
</div> {/if}
{/if}
{/key}
<style> <style>
.component { .component {