Basically, what it says. What is the point of <keep-alive>? This might sound silly, but I thought the purpose was to cache data associated with an component not currently being rendered in the DOM. According to this bug/issue, <keep-alive> is specifically designed to drop the cache it was holding when an element was removed from the page. So what am I missing?
Why would I want to use <keep-alive> with v-show? Isn't the whole point of v-show that the element still exists on the page, just has CSS set to hide it? By default, does an element lose data when it's hidden with v-show?
To be clear, the follow example is apparently supposed to not work (according to the closed bug/issue I linked anyway):
<div v-if="lazyLoaded && userClickedToShow">
<h2>{{someLazyLoadedData.title}}</h2>
<div id="otherStuff">
...
</div>
<keep-alive>
<some-child-component :prop="someLazyLoadedData"></some-child-component>
</keep-alive>
</div>
So I would have expected that <keep-alive> in this scenario would have cached data associated with the <some-child-component> once it was loaded, and if the user clicks to show (maybe it's a lot of data that I don't want in the DOM for performance reasons unless the user specifically clicks to show it, or whatever) it toggles the display, but keeps the search terms or whatever happened in the component.
Is there a way to rewrite this that would fit with how <keep-alive> is supposed to function? Do I have to bind to is on a <component> and just set it to nothing if I don't want it to render at the moment? Something like this?
<keep-alive>
<component :is="lazyLoaded && userClickedToShow ? 'SomeChildComponent' : ''" :prop="lazyLoaded && someLazyLoadedData"></component>
<keep-alive>
That seems to obfuscate what is actually happening there, if it even works. Also assuming that SomeChildComponent's prop can take false, which it might not be able to. I'm not a fan of that option. Slightly better I guess would be to wrap the whole thing in an if block, maybe?
<div v-if="lazyLoaded">
<keep-alive>
<component :is="userClickedToShow ? : 'SomeChildComponent' : ''" :prop="someLazyLoadedData"></component>
<keep-alive>
</div>
Of course, this assumes that <keep-alive> functions within a v-if block, which it might not. Also, it's still less clear than the first way (that doesn't work). I'm not a fan of setting is to '' unless that's really the only way. And of course, neither of these options allow for larger blocks to be controlled by the conditional, only the element being kept alive.
Just spent the better part of a two days trying to figure out why <keep-alive> was failing to keep anything alive! Hopefully there's something simple I'm just missing!
Edit: updated initial example to better reflect my use-case.
I thought the purpose was to cache data associated with an component not currently being rendered in the DOM
No, it doesn't cache component's data. It caches whole component instance (including it's whole state). Simply it makes the component instance to live instead of being destroyed...
According to this bug, is specifically designed to drop the cache it was holding when an element was removed from the page. So what am I missing?
Point to take from this "bug" is "whenever <keep-alive> component is destroyed (because it is itself inside v-if), it drops all cached components..."
Why would I want to use
<keep-alive>withv-show? Isn't the whole point ofv-showthat the element still exists on the page, just has CSS set to hide it?
Yes, it is exactly the point of v-show and it makes no sense to use it with <keep-alive> (because v-show does not result in component being destroyed/created)
By default, does an element lose data when it's hidden with
v-show?
No, the component hidden by v-show still exists in memory, in component tree and the DOM and keeps it's state....
To be clear, the follow example is apparently supposed to not work (according to the closed bug I linked anyway)
<div v-if="lazyLoaded && userClickedToShow">
<keep-alive>
<some-child-component :prop="someLazyLoadedData"></some-child-component>
</keep-alive>
</div>
...yes its doesn't work because :
v-if === false will destroy the <keep-alive> component if it was previously rendered (but it's not entirely correct because <keep-alive> is "render-less" in the sense it just provide functionality and doesn't render anything to the DOM except it's child component) .v-if === true will create the <keep-alive> and render it's child componentsIn order to make it work, you need to move <keep-alive> outside of v-if:
<keep-alive>
<some-child-component v-if="lazyLoaded && userClickedToShow" :prop="someLazyLoadedData" />
</keep-alive>
Above code should result in some-child-component to be rendered (and put inside <keep-alive>'s cache at the same time) when result of v-if condition is true. When v-if is switched to false, component's template is removed from DOM but component remains in the cache instead of being destroyed.
Main difference between v-if (together with <keep-alive>) and v-show in this case is that with v-if/keep-alive combo, the component instance is kept in the memory but result of it's template is not part of the DOM, whereas for v-show the component is alive and the corresponding HTML it renders is part of the DOM (just hidden)
And to answer your question....<keep-alive> is primarily designed for dynamic component's (<component :is="" >) and Vue-router in particular...
<div v-if="lazyLoaded && userClickedToShow">
<h2>{{someLazyLoadedData.title}}</h2>
<div id="otherStuff">
...
</div>
<keep-alive>
<some-child-component :prop="someLazyLoadedData"></some-child-component>
</keep-alive>
</div>
This code won't work as expected for the same reason as 1st example - if keep-alive is destroyed (as a result of v-if condition evaluated to false), it will drop all cached components. keep-alive is simply local cache which will work only if it is itself "rendered".
Is there a way to rewrite this that would fit with how is supposed to function?
Your best option is just to wrap everything you want "toggle" into single component and use that component like this:
<keep-alive>
<my-component v-if="lazyLoaded && userClickedToShow" :prop="someLazyLoadedData" />
</keep-alive>
...all other variants will fail as you can try and see in this demo
Docs
Note,
<keep-alive>is designed for the case where it has one direct child component that is being toggled. When there are multiple conditional children,<keep-alive>requires that only one child is rendered at a time.
<div)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With