diff --git a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte index 243817dfda..535b947f5f 100644 --- a/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/userInterface/AppPreview/CurrentItemPreview.svelte @@ -22,27 +22,37 @@ ? screenPlaceholder : $store.currentPreviewItem $: selectedComponentId = $store.currentComponentInfo?._id ?? "" - $: previewData = { - page, - screen, - selectedComponentId, - } + + // Saving pages and screens to the DB causes them to have _revs. + // These revisions change every time a save happens and causes + // these reactive statements to fire, even though the actual + // definition hasn't changed. + // By deleting all _rev properties we can avoid this and increase + // performance. + $: json = JSON.stringify({ page, screen, selectedComponentId }) + $: strippedJson = json.replaceAll(/"_rev":\s*"[^"]+"/g, `"_rev":""`) // Update the iframe with the builder info to render the correct preview - const refreshContent = () => { + const refreshContent = message => { if (iframe) { - iframe.contentWindow.postMessage(JSON.stringify(previewData)) + iframe.contentWindow.postMessage(message) } } // Refresh the preview when required - $: refreshContent(previewData) + $: refreshContent(strippedJson) // Initialise the app when mounted onMount(() => { - iframe.contentWindow.addEventListener("bb-ready", refreshContent, { - once: true, - }) + iframe.contentWindow.addEventListener( + "bb-ready", + () => { + refreshContent(strippedJson) + }, + { + once: true, + } + ) }) diff --git a/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js b/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js index 2d25aea92b..6c18def11b 100644 --- a/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js +++ b/packages/builder/src/components/userInterface/AppPreview/iframeTemplate.js @@ -32,9 +32,11 @@ export default ` selectedComponentStyle.appendChild(document.createTextNode(selectedCss)) // Set some flags so the app knows we're in the builder - window["##BUDIBASE_IN_BUILDER##"] = true; - window["##BUDIBASE_PREVIEW_PAGE##"] = page; - window["##BUDIBASE_PREVIEW_SCREEN##"] = screen; + window["##BUDIBASE_IN_BUILDER##"] = true + window["##BUDIBASE_PREVIEW_PAGE##"] = page + window["##BUDIBASE_PREVIEW_SCREEN##"] = screen + window["##BUDIBASE_SELECTED_COMPONENT_ID##"] = selectedComponentId + window["##BUDIBASE_PREVIEW_ID##"] = Math.random() // Initialise app if (window.loadBudibase) { diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 1d9308ca26..90428dbf34 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -4,7 +4,7 @@ import * as ComponentLibrary from "@budibase/standard-components" import Router from "./Router.svelte" import { enrichProps } from "../utils/componentProps" - import { bindingStore } from "../store" + import { bindingStore, builderStore } from "../store" export let definition = {} @@ -32,12 +32,20 @@ const name = split?.[split.length - 1] return name === "screenslot" ? Router : ComponentLibrary[name] } + + // Returns a unique key to let svelte know when to remount components. + // If a component is selected we want to remount it every time any props + // change. + const getChildKey = childId => { + const selected = childId === $builderStore.selectedComponentId + return selected ? `${childId}-${$builderStore.previewId}` : childId + } {#if constructor} {#if children && children.length} - {#each children as child (child._id)} + {#each children as child (getChildKey(child._id))} {/each} {/if} diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 2925e950f6..fa0e3177f4 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -9,6 +9,8 @@ const loadBudibase = () => { inBuilder: !!window["##BUDIBASE_IN_BUILDER##"], page: window["##BUDIBASE_PREVIEW_PAGE##"], screen: window["##BUDIBASE_PREVIEW_SCREEN##"], + selectedComponentId: window["##BUDIBASE_SELECTED_COMPONENT_ID##"], + previewId: window["##BUDIBASE_PREVIEW_ID##"], }) // Create app if one hasn't been created yet diff --git a/packages/client/src/store/builder.js b/packages/client/src/store/builder.js index 4b197596be..04363263c3 100644 --- a/packages/client/src/store/builder.js +++ b/packages/client/src/store/builder.js @@ -5,6 +5,8 @@ const createBuilderStore = () => { inBuilder: false, page: null, screen: null, + selectedComponentId: null, + previewId: null, } return writable(initialState) }