All questions

Strapi + Vue SPA, variant flashes after the default renders

Asked by nikos_p on

Nnikos_p

hey, we have a classic SPA, Vue 3 + Strapi backend, no SSR. I'm fetching the personalized hero like this:

<script setup>import {ref, onMounted} from 'vue';import croct from '@croct/plug';
const hero = ref(null);
onMounted(async () => {    const {content} = await croct.fetch('home-hero');    hero.value = content;});</script>

Works, but users see the Strapi default hero for a beat and then the variant swaps in. Looks cheap on slower connections. Is there a way to aviod the flash without migrating the whole thing to Nuxt? that's not on the table this quarter

Was this helpful?

2 answers

Aandresv

The flash comes from when you fetch, not from the SPA itself. onMounted runs after the component has already rendered, so the default is on screen before the variant arrives. SPA support is flicker-free when the content is resolved before render rather than after mount.

Move the fetch into setup and await it, then gate the section behind Suspense:

<script setup>import croct from '@croct/plug';
const {content: hero} = await croct.fetch('home-hero');</script>

With a top-level await in setup the component becomes async, so wrap it in <Suspense> in the parent. The section then renders once, with the right content, no swap.

Also give the fetch a fallback so the Strapi default serves if the request fails for any reason:

const {content: hero} = await croct.fetch('home-hero')    .catch(() => ({content: strapiDefaultHero}));
Was this helpful?
Nnikos_p

moved it into setup with Suspense and the swap is gone. didn't realize the async setup pattern was all it took, thanks!

Kkatya_m

Small alternative if you would rather not introduce Suspense: keep the fetch in setup without await and gate just the hero markup with v-if="hero", rendering nothing (or a fixed-height skeleton) until content resolves. Same principle, resolve before you show anything, so there is never a default-to-variant swap.

Also, since you are on Vue anyway, the dedicated Vue SDK gives you a plugin and composables instead of the vanilla plug, which makes this pattern a bit less manual. But either approach kills the flash.

Was this helpful?
Still have questions?