How to Implement Force Unmount in Vue 3 When Deactivated

I've developed a VUE app that makes use of the keep-alive method in the router. There are multiple pages that should only be loaded once, but certain specific pages need to be reloaded every time they are activated.

<template>
  <router-view v-slot="{ Component }">
    <keep-alive max="5">
      <component :is="Component" />
    </keep-alive>
  </router-view>
<template>

My goal is to remove a page-component from the keep-alive cache when it is deactivated.

/* This component has been loaded */
export default {
  setup() {
    const state = ref({});
    /* Initialize and load data...*/
   
    onDeactivated(() => {
     // Need to unmount this component ???
    });
    
    return { state };
  },
  components: {},
};

In your opinion, what would be the best practice for achieving this?

Answer №1

Custom Conditional keep-alive

If you want to control when components are added or removed from the keep-alive cache, you can use a reactive set and bind it to the exclude property of keep-alive. Here's how to do it:

// App.vue
import { provide, reactive, computed } from 'vue'

export default {
  setup() {
    const keepAliveExcludes = reactive(new Set())

    provide('keepAliveExcludes', {
      add: name => keepAliveExcludes.add(name),
      remove: name => keepAliveExcludes.delete(name),
    })

    return {
      keepAliveExcludes: computed(() => Array.from(keepAliveExcludes))
    }
  }
}

In your template, bind keepAliveExcludes to the <keep-alive>.exclude property:

<template>
  <router-view>
    <keep-alive :exclude="keepAliveExcludes">
      ...
    </keep-alive>
  </router-view>
</template>

In the child route component, use inject to access the keepAliveExcludes and manage its entries based on user interactions:

<template>
  <h1>About</h1>
  <div>
    <label>Keep Alive
      <input type="checkbox" v-model="keepAlive">
    </label>
  </div>
</template>

<script>
import { ref, inject, watchEffect } from 'vue'

export default {
  name: 'About',
  setup() {
    const { add: addKeepAliveExclude, remove: removeKeepAliveExclude } = inject('keepAliveExcludes', {})

    const keepAlive = ref(true)
   
    watchEffect(() => {
      if (keepAlive.value) {
        removeKeepAliveExclude?.('About')
      } else {
        addKeepAliveExclude?.('About')
      }
    })

    return { keepAlive }
  },
}
</script>

Check out the demo here

Forced Exclusion in keep-alive

If you always want a component to be excluded from the keep-alive cache, you can simply specify the component name without using the dynamic approach above.

In your template, directly list the component name in the <keep-alive>.exclude property:

<template>
  <router-view>
    <keep-alive exclude="About">
      ...
    </keep-alive>
  </router-view>
</template>

View the demonstration here

Answer №2

Check out the fantastic response from @tony19, although it seems to be encountering some issues due to a potential bug in VUE (I'm currently using version 3.2.6).

The problem arises when a component is excluded from being kept alive after it's initiated, and then the maximum number of keep-alive components is reached. VUE attempts to remove the non-existent excluded component, causing an error that halts the application. More details on this error can be found below.

To resolve this issue, I decided to build upon Tony19's excellent solution. Instead of excluding the component after it has loaded, I set up rules in the router just before loading the component.

const routes = [
  /* ... */
  {
    path: "/about",
    name: "AboutPage",
    meta: { excludeKeepAlive: true },
    component: () => import('./../components/AboutPage.vue'),
  }
  /* ... */
];

Here is how this approach was implemented in the main APP:

/* Main app logic goes here */
export default {
  setup() {
    /* ... */
    const keepAliveExcludes = reactive(new Set());

    cont keepAliveExcluder= {
      add: name => keepAliveExcludes.add(name),
      remove: name => keepAliveExcludes.delete(name),
    }
   
    router.beforeEach((to, from, next) => {    
      if(to.meta?.excludeKeepAlive===true){      
        keepAliveExcluder.add(to.name);
      } 
      next();
     });
    /* ... */
   return {
      keepAliveExcludes: computed(() => Array.from(keepAliveExcludes))
    }
   }
}

Further details on the error (potentially a bug)

The error is triggered at line 2057 of runtime-core.esm-bundler.js

Uncaught (in promise) TypeError: Cannot read property 'type' of undefined

This error occurs because VUE is unable to locate the dynamically excluded component.

https://i.sstatic.net/4e7SN.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An element in defaultProps deemed as nonexistent

As I dive into routes and routing practice, I've encountered some challenges that have me stumped. The issue seems to be in the render method in App.js. The concept is simple - I'm working on a getDogFunc function that should help me locate a s ...

The image source is visible in Vue.js, but unfortunately, my picture is not showing up

Below is the code and script that I have: <template> <div class="tasks_container"> <div class="tasks_content"> <h1>Tasks</h1> <ul class="tasks_list"> ...

Enhancing Vue.js functionality with v-model for seamless global data access

I am currently developing a web application that allows users to collaborate on projects. The app's architecture is structured in the following manner: Component A (the main app container) Components B1-Bn (including header, footer, and main window, ...

Creating a dynamic anchor scrolling effect within a dropdown select menu

Having trouble achieving smooth scrolling with a select option element, only works with a link. Any suggestions? Check out the jsfiddle demo to see what I mean! $(function() { $('a[href*=#]:not([href=#])').click(function() { if (location. ...

mention a particular anchor by clicking on it to refresh the webpage

Can a webpage automatically navigate to a specific anchor/tag when reloaded in the browser? Thanks in advance I came across this method: window.location.reload(); However, I'm searching for a solution that can detect the reload and then run a basi ...

Accessing User Input Data with JQuery

Can someone help me figure out how to store the input value from a Materialize select form in HTML using a variable in javascript/jquery? Here is the HTML code for the form: <div class="input-field col s12"> <select> <option va ...

Guidelines for integrating Pinia seamlessly into Vue 3 components

How should Pinia's store be correctly used in Vue 3 components? Option A const fooStore = useFooStore(); function bar() { return fooStore.bar } const compProp = computed(() => fooStore.someProp) Option B function bar() { return useFooStore( ...

Struggling to get a shader up and running on three.js using shaderfrom

Trying to add this shader to my project: This is the fragment shader code: <script id="fragmentShader" type="x-shader/x-fragment"> #ifdef GL_ES precision highp float; precision highp int; #endif uniform vec2 u_resolutio ...

Setting a variable in a v-tab using Vuetify now only takes 2 easy clicks!

I'm currently utilizing Vuetify and vuejs to develop a tab system with 3 tabs. The tabs are being switched dynamically by binding to the href of a v-tab. Each time I click on a tab, the value of the speed variable is modified. However, I'm encoun ...

Executing PHP function through AJAX

I have thoroughly researched various resources regarding my issue but still have not been able to find a solution. My goal is to retrieve the result of a PHP function using jQuery AJAX. function fetch_select(){ val_name = $('#name').val(); ...

Updating records in Laravel 6 with Vue.js from a child component utilizing vue-router and axios

For the past week, I've been struggling with the update method in Vue Components. The issue arises when a user tries to update by clicking the "update" button which opens a modal. Within the modal, the child component value updates successfully, but I ...

When a new element is added to the DOM, bind a click event to it that will trigger another

When I add an element to the DOM, I bind it with a click function. The problem is that if I add multiple elements and click on any of them, the function triggers multiple times. What causes this behavior and is there a better way to achieve the desired res ...

Submitting an HTML form to trigger a PHP function through AJAX

I am currently working on a task that involves POSTing an email address entered in an HTML form to a PHP script for storage in a database. The script should also handle error messages if the user inputs an invalid email address. I want to make this process ...

Displaying information based on selection in AngularJSIn this tutorial

I am a beginner in Angularjs and currently working on developing a website. One of the tasks I have is to create a combo box that, when an option is selected, calls a method to load values into a Scope variable and update it. Below is the code I have so fa ...

What is the best way to retrieve all the values of a specific field from a store?

Is there a way to retrieve all the values of a specific field from a store without manually selecting each cell? In my grid, I am looking to extract all the values from a particular column directly from the store. Is this achievable without any manual sel ...

Accessing a hyperlink in an alternative browser

Is there a way to transfer a link from one browser to another? For example, moving a link from Firefox to Chrome or from a Chrome Incognito window to a regular Chrome window. Let me provide more context. I have a webpage that refreshes every second and us ...

A guide on implementing the stencilFunc method in Three.js

Is it possible to utilize stencilFunc and stencilOp functions within Three.js? I attempted to incorporate code for a stencil test but encountered issues. var scene = new THREE.Scene(); var renderer = new THREE.WebGLRenderer({ antialias: true, st ...

Can the Route be modified in Next.js?

I have developed search functionality that navigates to "/search/xxxx", but it is located in the header. Every time I perform a search, the route gets repeated and becomes "/search/search/xxx". Could you suggest any way other than usin ...

Is there a way to convert HTML into a structured DOM tree while considering its original source location?

I am currently developing a user script that is designed to operate on https://example.net. This script executes fetch requests for HTML documents from https://example.com, with the intention of parsing them into HTML DOM trees. The challenge I face arise ...

Ways to identify input that has been altered dynamically

I'm currently trying to figure out why I can't seem to detect any input changes with the code snippet below: $("#fname").on("change", function () { console.log("The text has been changed."); }); $("button").o ...