Vue: keep-alive no longer caches a component after calling $destroy on it once

Created on 3 Nov 2018  路  6Comments  路  Source: vuejs/vue

Version

2.5.17

Reproduction link

https://jsfiddle.net/hellix08/y4Lqvj6u/

Steps to reproduce

You are viewing component 'Base' and a counter that shows how many times it's created() lifecycle hook has been called.

1) Click 'Next' to go to component 'Confirm'.

2) Click on 'Yes' to go back to 'Base' while also destroying it. It's created() calls counter has increased which is expected.

3) If you now click 'Next' to go back to component 'Confirm' and press 'No', though, you'll see that it's created() counter has increased.

If you keep pressing 'Next' then 'No' you'll see the created() calls counter keeps increasing even though it didn't before destroying it.

What is expected?

After manually destroying component 'Base', it is reacreated once and cached by keep-alive.

What is actually happening?

After manually destroying component 'Base', keep-alive creates another instance but no longer caches it, recreating a new instance every time it is shown.


I've run into this bug using Vue router but I've fiddled around with it and noticed it has to do with keep-alive.
I'm pretty sure it doesn't have to do with the fact that $destroy is being called just before showing the same component again. In my project the component being destroyed was recreated after another 2-3 components have been shown and the issue remains the same.

Most helpful comment

That's not what I wanted to achieve @posva, I want Base to be destroyed when I press Yes so that the next time I get a clean instance of it. But the issue is that the new instance isn't cached anymore.

All 6 comments

You shouldn't call $destroy manually in general but with keep-alive you cannot call it as it will actually destroy the component. However, you can use a v-if to let keep-alive actually handle the recreation: https://jsfiddle.net/baqnhdt7/

That's not what I wanted to achieve @posva, I want Base to be destroyed when I press Yes so that the next time I get a clean instance of it. But the issue is that the new instance isn't cached anymore.

@eliaperantoni Hi, I have the same requirements, I have a tabbed system and it's not practical ho keep all tabs ever opened in the system cached, a user could easily open hundreds of tabs. So, when a user click on the close button for that tab I want to destroy the component that was kept alive. The problem is that after destroying the component the new instance isn't cached anymore. Is there a solution for this?

@marceloatg Hi! Back when I was working on this, I found a little trick.

<keep-alive>
  <YourComponent :key="cache"></YourComponent>
</keep-alive>

Where cache is an integer.
To get a fresh instance of YourComponent:

  1. Call this.$destroy() inside YourComponent
  2. Increment cache by one

keep-alive will treat instances with different keys individually.
What is happening here (or I guess it is) is that, you destroy the old instance, but then you increment the key by one, keep-alive will recognize that as a completely new instance and so will discard everything it knows about the old instance.

It has worked well so far.
It's not the cleanest solution but it gets the job done and it shouldn't leave much garbage behind as I've tested it with vue tools.

@eliaperantoni Thank you so much! Your solution worked perfectly. The code I have right now is:

<keep-alive>
  <router-view :key="getRouterViewKey"/>
</keep-alive>

Where the getRouterViewKey is a computed that updates the key when necessary.

Once again, thank you for the quick response, you saved me a lot of time!

Very glad to hear it helped 馃槃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bfis picture bfis  路  3Comments

franciscolourenco picture franciscolourenco  路  3Comments

6pm picture 6pm  路  3Comments

robertleeplummerjr picture robertleeplummerjr  路  3Comments

aviggngyv picture aviggngyv  路  3Comments