Composition-api: Returned ref stays `null` if it's connected to a conditionally shown `slot`

Created on 29 Mar 2020  路  1Comment  路  Source: vuejs/composition-api

Here is a problem: barRef is always null, although getCurrentInstance().$refs.barRef is not.

codesandbox example

  1. open the codesandbox example
  2. wait for 4 seconds so the bar component is rendered.
  3. wait for 10 seconds and then click on the getbar button
  4. look at the console. you will get null and ref value. which is bad, cause it should be ref-value in both logs.

Here what I did:
I create a foo component that do calculations, and when the calculations are done it need to render whatever inside the slot. (not before) by using v-if.

In the component that host the foo component, I need to access the component inside (where the slot content) by click on button event.

I wait for 10 seconds and click on the button. (because after ten seconds, the component should be rendered and available on the dom).

but when I console.log the barRef I get null, and when I console.log the getCurrentInstance().$refs.barRef I get the ref.

The code:

import Vue from "vue";
import VueCompositionApi, { getCurrentInstance } from "@vue/composition-api";

import { ref } from "@vue/composition-api";

import VueRouter from "vue-router";

Vue.use(VueCompositionApi);

Vue.use(VueRouter);

const foo = {
  template: `
  <div>
    <h3>im foo</h3>
    <slot v-if="showSlot"></slot>
   </div>
  `,
  setup() {
    const showSlot = ref(false);

    setTimeout(() => {
      showSlot.value = true;
    }, 4000);
    return { showSlot };
  }
};

Vue.component("foo", foo);

const bar = {
  template: `
    <div>
      <h4>im bar</h4>
    </div>
  `
};

Vue.component("bar", bar);

const App = {
  template: `
  <div>
    <h1>im app</h1>

    <foo>
     <bar ref="barRef"></bar>

    </foo>

    <button @click="getBar">getBar</button>
  </div>
  `,
  setup() {
    const barRef = ref(null);
    const vm = getCurrentInstance();

    function getBar() {
      console.log({ barRef: barRef.value });
      console.log({ vm$refsbarRef: vm.$refs.barRef });
    }

    return { barRef, getBar };
  }
};

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

bug help wanted

>All comments

Hm. That's a tough one ...

We check the current refs on mounted and updated (with a mixin) and assign their values to the matching properties that were returned by setup - if any.

The problem here is, that in mounted, the ref doesn't exist yet - it only exists after the child (<foo>) has updateda few seconds later.

But when <foo> updates, the parent, our component, doesn't get notified about that. our component's updated hook won't run at that moment - and rightfully so.

I don't really see a good way to fix this right now, open for ideas ...

Was this page helpful?
0 / 5 - 0 ratings