"Non-function value encountered for default slot." in Vue 3 Composition API component

The warning is about the array of VNodes created in the setup()'s render function in Composite.js.

// src/components/Composite.js
export default defineComponent({
  setup(props, { slots }) {
    return () =>
      h(HelloWorld, {}, [h("div", {}, ["Div 1"]), h("div", {}, ["Div 2"])]);
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  }
});

This is inefficient because the child slot is rendered before the HelloWorld component could even use it. The child slot is essentially rendered in the parent, and then passed to the child. Wrapping the child slot generation in a function defers the work until the child is rendered.

I don't understand what is the difference if I use the slots from a template or from an other component.

@vue/compiler-sfc compiles the <template> from SFCs into a render function, where slots are passed as functions, which avoids the warning you observed.

Solution

Instead of rendering the child slot in the parent (i.e., passing an array of VNodes as the slots argument directly), wrap it in a function:

// src/components/Composite.js
export default defineComponent({
  setup(props, { slots }) {
    return () =>          👇
      h(HelloWorld, {}, () => [h("div", {}, ["Div 1"]), h("div", {}, ["Div 2"])]);
  }
});

Note the inner h() calls don't need this function wrapper because they're all rendered together with the default slot by the child.

demo