Home > front end >  Cannot use TransitionGroup in render function while building my custom Tabs component
Cannot use TransitionGroup in render function while building my custom Tabs component

Time:05-10

As I've wrote in the title, I'm trying to build my own Tabs components. So far it's very basic:

Tabs.vue

setup(props, { slots }) {
  const { activeTab } = toRefs(props);
  provide("activeTab", activeTab);

  const newSlots = slots.default().map((slot, index) => {
    return h(slot, {
      index, // for each tab to know, whether is active
      key: index, // for TransitionGroup
    });
  });

  return () =>
    h(
      TransitionGroup,
      {
        name: "tabs-fade",
      },
      () => newSlots
    );
}

Tab.vue

<template>
  <div v-if="activeTab === index">
    <slot />
  </div>
</template>
setup() {
  const activeTab = inject("activeTab");

  return {
    activeTab,
  };
},

And I've planned to use it like that: Testing.vue

<ul>
  <li @click="activeTab = 0">1</li>
  <li @click="activeTab = 1">2</li>
  <li @click="activeTab = 2">3</li>
</ul>
<Tabs :activeTab="activeTab">
  <Tab> 1 </Tab>
  <Tab> 2 </Tab>
  <Tab> 3 </Tab>
</Tabs>

Without TransitionGroup everything works fine, although when I'm trying to add it for smoother transitioning, I'm getting an error when trying to switch between the tabs:

[Vue warn]: Unhandled error during execution of render function 
  at <TransitionGroup name="tabs-fade" > 
  at <Tabs activeTab=1 > 
  at <Testing> 
  at <App>

[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core 
  at <TransitionGroup name="tabs-fade" > 
  at <Tabs activeTab=1 > 
  at <Testing> 
  at <App>
Uncaught (in promise) TypeError: child.el.getBoundingClientRect is not a function

Screenshot of errors

CodePudding user response:

TransitionGroup expects a consistent number of children so that it can transition from one state to another. Currently, Tabs.vue's root element is conditionally rendered, such that it's possible for there to be no element at all when the condition is not met, leading to the crash:

<!-- Tab.vue -->
<template>
  <div v-if="activeTab === index"> ❌ when false, no element exists
    <slot/>
  </div>
</template>

Solution

Add a v-else on a div to ensure an element always exists in Tab.vue:

<!-- Tab.vue -->
<template>
  <div v-if="activeTab === index">
    <slot/>
  </div>
  <div v-else />            
  • Related