You’re correct: the challenge is that <Suspense> will mount the child component (and thus trigger its async logic) as soon as the panel is rendered in the DOM, regardless of whether the panel is visible/collapsed. The <SplitterPanel>'s @expand event is also fired on initial mount if the panel is expanded by default, which complicates things.
Goal:
- Only load (and render)
<LookingGlassWrapper>(and thus callupdateLookingGlassNodes()) when the user first expands the panel. - Still use
<Suspense>for async loading fallback.
Solution
Key idea:
Don’t render <LookingGlassWrapper> (and thus <Suspense>) until the panel is actually expanded for the first time.
You can do this by using a flag that you set on the <SplitterPanel>'s @expand event, and then use v-if to conditionally render the <Suspense> block.
1. Track if the panel has ever been expanded
Add a lookingGlassPanelActive ref in your parent (App.vue):
const lookingGlassPanelActive = ref(false);
function onLookingGlassPanelExpand() {
// Only set to true the first time
if (!lookingGlassPanelActive.value) {
lookingGlassPanelActive.value = true;
}
}
2. Use @expand on <SplitterPanel>
Update your <SplitterPanel> for Looking Glass to:
<SplitterPanel
ref="lookingGlassPanelRef"
class="bg-white"
collapsible
:collapsed-size="0"
:min-size="0"
@expand="onLookingGlassPanelExpand"
>
<template v-if="lookingGlassPanelActive">
<Suspense>
<template #fallback>
<p class="bg-red-700">Loading nodes...</p>
</template>
<LookingGlassWrapper />
</Suspense>
</template>
</SplitterPanel>
- The
<template v-if="lookingGlassPanelActive">ensures the wrapper (and thus its async logic) only mounts when the user expands the panel. - The
@expandevent is only fired when the panel is expanded (not collapsed), so this works as intended.
3. Remove the await loadNodes() from LookingGlassWrapper's top-level
Instead, in LookingGlassWrapper.vue, you can keep your async logic as-is, since it will only run when the component is mounted (which now only happens when the user expands the panel):
<script setup>
import LookingGlassPane from "@looking-glass/drawer/LookingGlassPane.vue";
import { useLookingGlass } from "@composables/useLookingGlass.js";
const { splitViewEnabled, nodeList, updateLookingGlassNodes } = useLookingGlass();
const loadNodes = async () => {
if (Object.entries(nodeList.value).length === 0) {
await updateLookingGlassNodes();
}
};
await loadNodes();
</script>
4. Summary
- The panel is collapsed by default.
<LookingGlassWrapper>(and its async loading) is only mounted/rendered when the user expands the panel for the first time.<Suspense>still works as expected for async fallback.
Full Example (relevant part)
App.vue:
<script setup>
import { ref, nextTick, onMounted } from "vue";
// ... other imports
const lookingGlassPanelRef = ref(null);
const lookingGlassPanelActive = ref(false);
function onLookingGlassPanelExpand() {
if (!lookingGlassPanelActive.value) {
lookingGlassPanelActive.value = true;
}
}
onMounted(() => {
nextTick(() => {
lookingGlassPanelRef.value?.collapse();
});
});
</script>
<template>
<!-- ... -->
<SplitterPanel
ref="lookingGlassPanelRef"
class="bg-white"
collapsible
:collapsed-size="0"
:min-size="0"
@expand="onLookingGlassPanelExpand"
>
<template v-if="lookingGlassPanelActive">
<Suspense>
<template #fallback>
<p class="bg-red-700">Loading nodes...</p>
</template>
<LookingGlassWrapper />
</Suspense>
</template>
</SplitterPanel>
<!-- ... -->
</template>
This approach ensures your async loading logic only runs when the user opens the panel, while still leveraging <Suspense> for loading feedback.