Documentation for emitting events with the Composition API not enitirely clear (typed on not typed)
Hello!
I'm working on a project where we've moved to Vue 3 and Nuxt 3 and we're starting to make more use of the Composition API. I'd like to say firstly that I enjoy the Composition API overall. I'm glad it's an option we have with Vue 3, and I appreciate in the documentation that there's a toggle to view either the Options or Composition API where it's relevant.
One problem we are seeing is with defineEmits along with computed() for computed refs. It seems that emitting events doesn't work as explained in the documentation. To help, I'll give an example that roughly outlines what my coworkers and I are trying to achieve.
(For all I know, this could actually end up as an issue to put in to Vue's core or Nuxt 3. Or we've just fudged something and we haven't noticed it yet.)
So say we have some tabs where we want to change data upon clicking one of the other tabs. We have a generic container for the tabbed data:
// TabbedContainer.vue
<script setup lang="ts">
import { ref, Ref } from '@vue/reactivity';
interface Props {
tabs: Array<{ name: string, id: string }>
}
/* One unclear thing here is if a return value needs to be specified for the event.
So would it be `(e: 'tab-selected', tag: string): string` ? */
const emit = defineEmits<{ (e: 'tab-selected', tag: string) }>();
// yay for destructing variables!
const { tabs = [] } = defineProps<Props>();
let tabSelected: Ref<string | null> = ref(null);
const selectTab = (tabId: string): void => {
tabSelected.value = tabId;
// this next line is what I assume we're supposed to do
emit('tab-selected', tabSelected.value);
}
// since created() doesn't exist in the Composition API
if (tabs.length != 0) tabSelected.value = tabs[0].id;
</script>
<!-- Somewhere down here we have a v-for="(tab in tabs), a @click="selectTab(tab.id)" on an <li></li>.
Then further down a <slot></slot> to put how our data is represented inside of this container -->
Pretty straight forward going off of what the docs say. The above component will get used on pages rather than in another component.
// pages/some-page/index.vue
<script setup lang="ts">
import { ref, Ref, reactive, computed, ComputedRef } from '@vue/reactivity';
interface Info {
name: string,
image: string,
}
// our data
let initialCount: Ref<number> = ref(12);
const tabs = reactive([]); // pretend there's data in there
const cardInfo = reactive([{}]) // here too
const currentTab: Ref<string> = ref('tab-one');
// computed props
const cards: ComputedRef<Info[]> = computed((): Info[] => { return cardInfo[currentTab.value]});
const shownCards: ComputedRef<Info[]> = computed((): Info[] => {
return cards.value.slice(0, initialCount.value + 1);
});
// methods
// Here's the problem, e is the captured event that will return a value.
const getTab = (e: any): void => currentTab.value = e;
const loadMore = (): void => {
if (cards.value.length > initialCount.value) {
initialCount.value += 12;
}
};
</script>
<!-- Somewhere down here we have the TabbedContainer component referenced with
it's event: @tab-selected="getTab".
The value of currentTab _does_ change, however what's shown inside of TabbedContainer
doesn't change.
Even though showCards is a computed reference and it references the value of currentTab,
and that has changed, the cards that are shown do not change. -->
The event is emitted properly and the value of a reference is changed, and a computed reference refers to that value of the changed reference. Unless I'm misunderstanding how computed references work in the new Composition API. #1661 also refers to the confusion with defining event emitters in the documentation, so at the very least it's not just me who's a bit confused.
Again, this could end up being an issue I need to put on the Vue Core project or Nuxt 3.
I recommend asking about this on Vue Land Discord: https://chat.vuejs.org/.
I'm unclear what documentation problem you'd like us to solve based on your description. It doesn't sound like a documentation problem, it sounds more like a bug in your code. But it'd need some back and forth to debug the problem properly, and Discord would be a better place to have that discussion.
We can try to figure out how to improve the docs once we know what the actual problem is.
@skirtles-code one thing I've found is that with <script setup> (at least with Nuxt 3) you cannot import things like ref, computed, etc. because I'm assuming those are looked for and expanded at compile-time and...well, I'm not entirely why.
I'm going to close this.
I'm unclear what problem is being described, so I can't attempt to fix it. I'd be happy to reopen this issue if a specific problem with the documentation can be identified.