###The Problem
I have a child component that may or may not exist on the page with a v-if
. Trying to keep it cached when the user has clicked other things so that search terms and whatnot show up again when the user returns fails no matter how I try to cache with <keep-alive>
.
###What I've tried
The documentation seems to indicate that all I need to do is wrap my component in a <keep-alive>
tag and things should just work. I tried matching some documentation that uses the <component>
tag which clearly doesn't work. I also tried using the include
prop since just wrapping it doesn't work.
Vue.component('child', {
template: '<div>child: {{text}}<div>',
data() {return {text: ""}},
created(){
this.$nextTick(() => {
this.text = `${Math.round(Math.random() * 100)}`
})
},
activated: function() {
this.$nextTick(() => {
console.log('in activated');
});
}
})
var vm = new Vue({
el: '#app',
data: function() {
return {
showNow:false,
message: 'This is a test.'
}
},
methods: {
changeText: function() {
this.message = 'changed';
},
toggle() {
this.showNow = !this.showNow
}
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<keep-alive include="child">
<div v-if="showNow">
<h4>Title of section to be toggled</h4>
<component is="child"></component>
</div>
</keep-alive>
<button @click="toggle()">toggle child</button>
</div>
I've also tried not using include
and just wrapping like so <keep-alive><child></child></keep-alive>
or using the <component>
syntax and neither of those work either.
If you remove the conditional rendering, the activated
hook is called, but that obviously defeats the purpose of <keep-alive>
! As it stands right now, that hook is never called, which is frustrating.
Also, the example in the documentation doesn't help either because they're not using v-if
, just changing which components are rendered via a string....
P.S. I have no idea how to tag this other than Vue.js
Here is a lightly modified version of your code with keep-alive
working correctly:
Vue.component('child', {
template: '<div>child: {{text}}</div>',
data() {return {text: ""}},
created(){
console.log('in created')
this.$nextTick(() => {
this.text = `${Math.round(Math.random() * 100)}`
})
},
activated: function() {
this.$nextTick(() => {
console.log('in activated');
});
}
})
var vm = new Vue({
el: '#app',
data: function() {
return {
showNow:false,
message: 'This is a test.'
}
},
methods: {
changeText: function() {
this.message = 'changed';
},
toggle() {
this.showNow = !this.showNow
}
},
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<keep-alive>
<child v-if="showNow"></child>
</keep-alive>
<button @click="toggle()">toggle child</button>
</div>
The created
hook is only called the first time. On subsequent activation the activated
hook is called but not created
.
The key change is that the <child>
component must be a direct child of <keep-alive>
. This direct child must also be the component that has the v-if
.
You can't use a <div>
for this purpose as <keep-alive>
specifically looks for a component, not just an element. See:
https://github.com/vuejs/vue/blob/ec78fc8b6d03e59da669be1adf4b4b5abf670a34/src/core/components/keep-alive.js#L85
Another common mistake with keep-alive
is to put a v-if
on the keep-alive
component itself, or on one of its ancestors. This won't work as the keep-alive
component itself will be destroyed. The keep-alive
component maintains a cache of child components but if the keep-alive
is itself destroyed then that cache is lost.
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