Home > OS >  Handling default slot on custom component
Handling default slot on custom component

Time:08-22

Iam stugging on a problem to handle default slots with render() function.

I have two components, one that passes a string value innerHTML to my custom Component MySub. In MySub i wants to use the default slot to do further stuff with it.

My Parent:

import { defineComponent, h, VNode } from "vue";
import MySub from "./mySub.ts"

export default defineComponent({
  render() {
    return h(MySub, {}, 'innerHTML')
  }
})

My Sub:

import { defineComponent, h, VNode } from "vue";

export default defineComponent({
  data() {
    return {
      value: ''
    }
  },
  mounted() {
    if (this.$slots.default && this.$slots.default()[0]) this.value = <string>this.$slots.default()[0].children
  },
  render() {
    return h('div', {}, [this.value   ' "here my added Stuff"'])
  }
})

Now to my problem: When i code it like this (above or link below), i get a warning calls: Non-function value encountered for default slot. Prefer function slots for better performance. I know whats todo to get rid of these message and why its exists. Just add a function call to the value in my MyParent return h(MySub, {}, () => 'innerHTML').

But when i do this, it get the following message: Slot "default" invoked outside of the render function: this will not track dependencies used in the slot. Invoke the slot function inside the render function instead. Also here, i know what the message wants to tell me, but i cant find a why to handle these problem.

I hope, i could explain my problem clear enough and somebody know what i can do.

Here is an Playground Example that reproduce exactly my problem.

CodePudding user response:

Dont know its the correct way to reply my own question, but i found and resolved the problem...

The problem isnt occur in the parent component. You always should call default slots within a function call like: () => 'innerHTML' for better performance (like the warn message is calling) cause to not render it, when its empty.

So i have to search for the problem in the child...

And the problem was the function mounted()

m̶o̶u̶n̶t̶e̶d̶(̶)̶ ̶{̶
  i̶f̶ ̶(̶t̶h̶i̶s̶.̶$̶s̶l̶o̶t̶s̶.̶d̶e̶f̶a̶u̶l̶t̶ ̶&̶&̶ ̶t̶h̶i̶s̶.̶$̶s̶l̶o̶t̶s̶.̶d̶e̶f̶a̶u̶l̶t̶(̶)̶[̶0̶]̶)̶ ̶t̶h̶i̶s̶.̶v̶a̶l̶u̶e̶ ̶=̶ ̶t̶h̶i̶s̶.̶$̶s̶l̶o̶t̶s̶.̶d̶e̶f̶a̶u̶l̶t̶(̶)̶[̶0̶]̶.̶c̶h̶i̶l̶d̶r̶e̶n̶
}̶,̶

In the render() function, i used this.value that is declared outside in the data() and assigned in the mounted(). So i just had to put it inside like below:

getDefaultSlotValue() {
  if (this.$slots.default && this.$slots.default()[0]) this.value = <string>this.$slots.default()[0].children
},
render() {
  return h('div', {}, [this.getDefaultSlotValue()   ' "here my added Stuff"'])
}

Iam not sure, but the problem seems to be no problem, when you call the MySub directly (to see in App.vue), cause the mounted() is normally called after rendering. But i dont know, whats vue exactly doing under the hood.

Here an working Playground example

  • Related