Subscribe on changes!

App can't rerender when use `v-if` in slots

avatar
Jan 4th 2021

Version

3.0.5

Reproduction link

https://stackblitz.com/edit/vue-t57npn?file=src/App.vue

Steps to reproduce

  1. click the img, the app will set the state show to true
  2. the child component won't rerender

What is expected?

I hope the child component could rerender

What is actually happening?

onUpdate function won't run.

avatar
Jan 4th 2021

First of all, you should not directly manipulate the slot's VNode, your code is fragile, and I don't see any meaningful intentions of your code.

The reason for this issue is that the ref(show) in the slot only collects the rendering function of the child component as a dependency, but in the sub-components, because you use v-if, the slot will not be rendered, which causes the ref(show) to not collect any components as dependencies, so modifying its value is useless.

Try the modified version: https://codesandbox.io/s/nostalgic-dew-ms9s9?file=/src/App.vue

avatar
Jan 4th 2021

My intention is to have a container wrap the slot. When slot does not exist, this container does not exist either. However, the demo you gave cannot achieve the function I want. I don't want to give this control to the outside.😢

First of all, you should not directly manipulate the slot's VNode, your code is fragile, and I don't see any meaningful intentions of your code.

The reason for this issue is that the ref(show) in the slot only collects the rendering function of the child component as a dependency, but in the sub-components, because you use v-if, the slot will not be rendered, which causes the ref(show) to not collect any components as dependencies, so modifying its value is useless.

Try the modified version: https://codesandbox.io/s/nostalgic-dew-ms9s9?file=/src/App.vue

avatar
Jan 4th 2021

Use a computed() property.

export default {
  name: "HelloWorld",
  setup(props, { slots }) {
    const withText = computed(() => {
      const text = getFirstValidNode(slots.default?.({ withText: true }));
      return !!(text && isValidElementNode(text));
    });

    return { withText };
  },
};

https://codesandbox.io/s/trusting-leftpad-b2pfs?file=/src/components/HelloWorld.vue

avatar
Jan 4th 2021

Use a computed() property.

export default {
  name: "HelloWorld",
  setup(props, { slots }) {
    const withText = computed(() => {
      const text = getFirstValidNode(slots.default?.({ withText: true }));
      return !!(text && isValidElementNode(text));
    });

    return { withText };
  },
};

https://codesandbox.io/s/trusting-leftpad-b2pfs?file=/src/components/HelloWorld.vue

tks, it work. but I still have a question, why computed can collect dependencies of slots. as far as I know slots are not reactive. did I not understand the docs? https://v3.vuejs.org/guide/composition-api-setup.html#context