Lets say I have foo.vue
that I import into the parent as components named a
and b
and displayed according to a variable show
Now from the parent if I switch between components a
and b
without setting the show = null
I get all sorts of child state errors.
So I set show
to null
before setting it to the corresponding vue component like this
this.show = null
this.show = a // or b
but this does not work. component ends up with state of the previous. This is verified even on props that are not updated.
I made it work using timeout
toggle(show){
this.show = null
let that = this
setTimeout(() => {
that.show = show
}, 200)
}
Is there a better way ? That is not elegant to me
What I understand is that what is going on inside the child does not matter if the parents tells it to switch it should go from blank slate and rebuild ? But in my case it is not the case. Is there anything that could cause my issue ?
setting to null
forces a hard refresh somehow ?
My child component is complex with ajax call to retrieve a list but nothing out of the ordinary.
parent code
<template>
<div id="userAreaEventWrapper">
<div class="userarea-submenu">
<div v-on:click="toggle(comps.eventForm)" class='button-base-out'>
<div :class="isSelected(comps.eventForm)">
New Event
</div>
</div>
<div v-on:click="toggle(comps.events)" class='button-base-out'>
<div :class="isSelected(comps.events)">
My Events
</div>
</div>
<div v-on:click="toggle(comps.eventsAttending)" class='button-base-out'>
<div :class="isSelected(comps.eventsAttending)">
Attending
</div>
</div>
</div>
<EventForm v-if="show === comps.eventForm" @created="toggle(comps.events)" :mode="'create'"></EventForm>
<Events ref="events" :mode="currentMode" v-if="show === comps.events" @noResults="toggle(comps.eventForm)" :attending="false"></Events>
<AttendingEvents ref="attending" :mode="'home'" v-if="show === comps.eventsAttending" :attending="true"></AttendingEvents>
</div>
</template>
<script>
const EventForm = () => import( './event-form.vue')
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')
export default {
name: "UserEventComponent",
components:{
EventForm,
Events,
AttendingEvents
},
data(){
return{
comps:{
eventForm:1,
events:2,
eventsAttending:3
},
show: 2,
currentMode:'user',
}
},
methods: {
toggle(show){
this.show = null
let that = this
setTimeout(() => {
that.show = show
}, 200)
},
isSelected(n){
return n === this.show ? 'button-base-in button-base-in-hover' : 'button-base-in'
},
},
}
</script>
child
fetch api on mounted()
mounted() {
this.currentMode = this.mode
if(this.resumeData && this.resumeData.slug){
this.selectedSlug = this.resumeData.slug
} else {
this.resume(this.resumeData)
this.getEvents()
}
}
This part doesn't serve a good purpose:
const Events = () => import( './events.vue')
const AttendingEvents = () => import( './events.vue')
The core feature of JavaScript modules (this includes ES modules) are evaluated only once on first import, import( './events.vue')
resolves to the same component. It gives a better idea whats going on when a component is used under a single name.
What happens on show
update is that there's 1 events component instance in the same place in component hierarchy, so it's not re-mounted and just receives a set of new props, specified in <Events>
and <AttendingEvents>
respectively.
Sibling instances of the same component should be distinguished by key
:
<Events ref="events" key="events" ... ></Events>
<Events ref="attending" key="attending" ... ></Events>
It is used most times with v-for
but also applicable to all directives that affect component hierarchy - v-if
, etc.