I recently developed a Vue 3 component called "Tab" using the option API. Here is the code:
export default {
name: "Tab",
props: {
name: {required: true},
iconClass: {required: true},
selected: {default: false}
},
data() {
return {
isActive: false
}
},
mounted() {
this.isActive = this.selected;
},
created() {
this.$parent.tabs.push(this);
},
}
However, I now want to convert it using the composition API. This is the updated code:
import {onBeforeMount, onMounted, ref} from "vue";
export default {
name: "Tab",
props: {
name: {required: true},
iconClass: {required: true},
selected: {default: false}
},
setup(props, {parent}) {
const isActive = ref(false)
onBeforeMount(() => {
parent.tabs.push(this);
})
onMounted(() => {
isActive.value = props.selected;
})
return {isActive}
}
}
A warning message is showing in the console:
Unhandled error during execution of beforeMount hook
This seems to be related to this specific line of code:
parent.tabs.push(this);
Any suggestions or ideas for debugging?
*** UPDATE ***
The tabs component (parent) has the following setup:
name: "Tabs",
setup() {
const tabs = ref([])
const selectedTab = (selectedTab) => {
tabs.value.forEach(tab => {
tab.isActive = (tab.name === selectedTab.name);
})
}
return {tabs, selectedTab}
}
*** UPDATE 2 ***
Even after trying with provide/inject, the tabs do appear but do not change content when selecting another tab.
Here are the implementations for the "Tabs" component (parent):
<template>
<div>
<div class="nav-wrapper">
<ul class="nav nav-pills nav-fill flex-column flex-md-row">
<li class="nav-item" v-for="tab in tabs" :key="tab">
<a class="nav-link mb-sm-3 mb-md-0" @click="selectedTab(tab)" :class="{'active' : tab.isActive}" href="javascript:void(0)">
<i class="ni mr-2" :class="[tab.iconClass]"></i>{{ tab.name }}
</a>
</li>
</ul>
</div>
<div class="tab-content">
<slot></slot>
</div>
</div>
</template>
<script>
import {provide, ref} from "vue";
export default {
name: "Tabs",
setup() {
const tabs = ref([])
const selectedTab = (selectedTab) => {
tabs.value.forEach(tab => {
tab.isActive = (tab.name === selectedTab.name);
})
}
provide('tabs', tabs.value)
return {tabs, selectedTab}
}
}
</script>
And here's the "Tab" component code:
<template>
<div class="tab-pane fade show" :class="{'active' : isActive}">
<slot></slot>
</div>
</template>
<script>
import {onBeforeMount, inject, onMounted, ref} from "vue";
export default {
name: "Tab",
props: {
name: {required: true},
iconClass: {required: true},
selected: {default: false}
},
setup(props) {
const isActive = ref(false)
onBeforeMount(() => {
const tabs = inject("tabs")
tabs.push({
name: props.name,
iconClass: props.iconClass,
selected: props.selected,
})
})
onMounted(() => {
isActive.value = props.selected;
})
return {isActive}
}
}
</script>