bhylu.com

Advertisements

Vue Dynamic Components and KeepAlive

Retain a component instance when switching between local panels.

How it works

The component element selects a component dynamically. KeepAlive can cache a component instance instead of unmounting it when another view is selected. This is useful for a small set of panels whose drafts should survive a switch. Cached components have activation and deactivation lifetimes, so background subscriptions may need different handling from ordinary unmount cleanup.

Run the code

Use a separate empty learning folder with Node 22.12+ in the 22 series. The reviewed Node version is 22.15.1. Save all files below with their exact relative paths; downloads may keep only the basename, so create src and any tests folders as listed. This project pins Vue 3.5.44 and Vite 7.3.1. Run npm install, then npm run dev and open the local address Vite prints.

Bhylu has no Vue playground. SFCs, npm imports and routing need this local project; do not paste them into the plain HTML or JavaScript editor. Apache, MySQL and changes to Bhylu server settings are not required. The application is a fictional seed-swap learning fixture.

Example

src/App.vue

<script setup>
import { shallowRef } from "vue";
import PacketDraft from "./PacketDraft.vue";
import DeskNote from "./DeskNote.vue";
const panel = shallowRef(PacketDraft);
function switchPanel() {
  panel.value = panel.value === PacketDraft ? DeskNote : PacketDraft;
}
</script>

<template>
  <main>
    <h1>Riverside seed swap</h1>
    <button @click="switchPanel">Switch panel</button
    ><KeepAlive><component :is="panel" /></KeepAlive
    ><output data-result>Cached local panels</output>
  </main>
</template>

Expected result

A draft typed in the first panel remains after switching away and back.

Using shallowRef keeps imported component definitions from being deeply proxied. The example has two known panels, not an unbounded cache of arbitrary route identifiers. KeepAlive max, include and exclude can help bound a real cache. Test deactivated resource behaviour as well as retained input text.

src/PacketDraft.vue

src/PacketDraft.vue

<script setup>
import { ref } from "vue";
const name = ref("Beans");
</script>
<template>
  <label for="draft">Draft variety</label><input id="draft" v-model="name" />
</template>

src/DeskNote.vue

src/DeskNote.vue

<template><p>Collection closes at 16:00.</p></template>

Check APIs and version differences in the official Vue guide.