From 9dd60c1acaffd73bd1fec028c1ff89a6d641dd39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Ba=CC=88uerle?= Date: Mon, 18 Nov 2024 11:50:08 -0800 Subject: [PATCH] fix(svelte-vega): fix infinite update depth issues --- packages/svelte-vega/src/lib/Vega.svelte | 2 +- packages/svelte-vega/src/lib/VegaEmbed.svelte | 105 ++++++++++-------- packages/svelte-vega/src/lib/VegaLite.svelte | 2 +- 3 files changed, 60 insertions(+), 49 deletions(-) diff --git a/packages/svelte-vega/src/lib/Vega.svelte b/packages/svelte-vega/src/lib/Vega.svelte index 63a5d2c8..4d5f291e 100644 --- a/packages/svelte-vega/src/lib/Vega.svelte +++ b/packages/svelte-vega/src/lib/Vega.svelte @@ -16,7 +16,7 @@ options?: EmbedOptions; data: Record; signalListeners?: SignalListeners; - view: View | undefined; + view?: View; onNewView?: (view: View) => void; onError?: (error: Error) => void; } = $props(); diff --git a/packages/svelte-vega/src/lib/VegaEmbed.svelte b/packages/svelte-vega/src/lib/VegaEmbed.svelte index 4cd95fd5..84152267 100644 --- a/packages/svelte-vega/src/lib/VegaEmbed.svelte +++ b/packages/svelte-vega/src/lib/VegaEmbed.svelte @@ -2,7 +2,7 @@ import type { EmbedOptions, Result } from 'vega-embed'; import type { SignalListeners, View, VisualizationSpec } from './types'; - import { onDestroy } from 'svelte'; + import { onDestroy, untrack } from 'svelte'; import vegaEmbed from 'vega-embed'; import { WIDTH_HEIGHT } from './constants'; @@ -26,7 +26,7 @@ }: { options: EmbedOptions; spec: VisualizationSpec; - view: View | undefined; + view?: View; signalListeners?: SignalListeners; data: Record; onError?: (error: Error) => void; @@ -37,66 +37,77 @@ let prevOptions: EmbedOptions = $state({}); let prevSignalListeners: SignalListeners | undefined = $state(undefined); let prevSpec: VisualizationSpec = $state({}); - let prevData: Record = $state({}); let chartContainer: HTMLElement | undefined = $state(undefined); $effect(() => { - if (!shallowEqual(data, prevData)) { + data; + untrack(() => { update(); - } - prevData = data; + }); }); $effect(() => { - if (chartContainer !== undefined) { - // only create a new view if neccessary - if (!shallowEqual(options, prevOptions, WIDTH_HEIGHT)) { - createView(); - } else { - const specChanges = computeSpecChanges( - combineSpecWithDimension(spec, options), - combineSpecWithDimension(prevSpec, prevOptions) - ); - const newSignalListeners = signalListeners; - const oldSignalListeners = prevSignalListeners; + chartContainer; + options; + spec; + signalListeners; + untrack(() => { + if (chartContainer !== undefined) { + // only create a new view if neccessary + if (!shallowEqual(options, prevOptions, WIDTH_HEIGHT)) { + createView(); + } else { + const specChanges = computeSpecChanges( + combineSpecWithDimension(spec, options), + combineSpecWithDimension(prevSpec, prevOptions) + ); + const newSignalListeners = signalListeners; + const oldSignalListeners = prevSignalListeners; - if (specChanges) { - if (specChanges.isExpensive) { - createView(); - } else if (result !== undefined) { - const areSignalListenersChanged = !shallowEqual(newSignalListeners, oldSignalListeners); - view = result.view; - if (specChanges.width !== false) { - view.width(specChanges.width); - } - if (specChanges.height !== false) { - view.height(specChanges.height); - } - if (areSignalListenersChanged) { - if (oldSignalListeners) { - removeSignalListenersFromView(view, oldSignalListeners); + if (specChanges) { + if (specChanges.isExpensive) { + createView(); + } else if (result !== undefined) { + const areSignalListenersChanged = !shallowEqual( + newSignalListeners, + oldSignalListeners + ); + view = result.view; + if (specChanges.width !== false) { + view.width(specChanges.width); + } + if (specChanges.height !== false) { + view.height(specChanges.height); } - if (newSignalListeners) { - addSignalListenersToView(view, newSignalListeners); + if (areSignalListenersChanged) { + if (oldSignalListeners) { + removeSignalListenersFromView(view, oldSignalListeners); + } + if (newSignalListeners) { + addSignalListenersToView(view, newSignalListeners); + } } + view.runAsync(); + } + } else if ( + !shallowEqual(newSignalListeners, oldSignalListeners) && + result !== undefined + ) { + view = result.view; + if (oldSignalListeners) { + removeSignalListenersFromView(view, oldSignalListeners); + } + if (newSignalListeners) { + addSignalListenersToView(view, newSignalListeners); } view.runAsync(); } - } else if (!shallowEqual(newSignalListeners, oldSignalListeners) && result !== undefined) { - view = result.view; - if (oldSignalListeners) { - removeSignalListenersFromView(view, oldSignalListeners); - } - if (newSignalListeners) { - addSignalListenersToView(view, newSignalListeners); - } - view.runAsync(); } + prevOptions = options; + prevSignalListeners = signalListeners; + prevSpec = spec; } - prevOptions = options; - prevSignalListeners = signalListeners; - prevSpec = spec; - } + }); }); onDestroy(() => { diff --git a/packages/svelte-vega/src/lib/VegaLite.svelte b/packages/svelte-vega/src/lib/VegaLite.svelte index b5704037..a34b2093 100644 --- a/packages/svelte-vega/src/lib/VegaLite.svelte +++ b/packages/svelte-vega/src/lib/VegaLite.svelte @@ -16,7 +16,7 @@ options?: EmbedOptions; data: Record; signalListeners?: SignalListeners; - view: View | undefined; + view?: View; onNewView?: (view: View) => void; onError?: (error: Error) => void; } = $props();