«Значение, не являющееся функциональным, встречается для слота по умолчанию». в компоненте API композиции Vue 3

#vue.js #vuejs3 #vue-composition-api #slots

Вопрос:

МАКВЕ

https://github.com/hyperbotauthor/minvue3cliapp

MCVE в прямом эфире

https://codesandbox.io/s/white-browser-fl7ji

У меня есть приложение Vue 3 cli-сервис, которое использует компоненты API композиции со слотами.

HelloWorld Компонент отображает слоты, которые он получает, в div :

 // src/components/Helloworld.js
import { defineComponent, h } from "vue";

export default defineComponent({
  setup(props, { slots }) {
    return () => h("div", {}, slots);
  }
});
 

Composite Компонент использует HelloWorld в своей setup функции и заполняет свои слоты:

 // src/components/Composite.js
import { defineComponent, h } from "vue";

import HelloWorld from "./HelloWorld";

export default defineComponent({
  setup(props, { slots }) {
    return () =>
      h(HelloWorld, {}, [h("div", {}, ["Div 1"]), h("div", {}, ["Div 2"])]);
  }
});
 

Приложение использует оба способа визуализации одних и тех же двух дивов:

 <template>
  <!--<img alt="Vue logo" src="./assets/logo.png">-->
  Works with plain slots
  <HelloWorld>
    <div>Div 1</div>
    <div>Div 2</div>
  </HelloWorld>
  Triggers warning when slots are used from other component
  <Composite> </Composite>
</template>

<script>
import HelloWorld from "./components/HelloWorld";
import Composite from "./components/Composite";

export default {
  name: "App",
  components: {
    HelloWorld,
    Composite,
  },
};
</script>

<style>
</style>
 

Composite Компонент запускает это предупреждение:

 Non-function value encountered for default slot. Prefer function slots for better performance. 
 

То же самое предупреждение не срабатывает, когда я использую HelloWorld только шаблон.

Я не понимаю, в чем разница, если я использую слоты из шаблона или из другого компонента.

В чем смысл этого предупреждения?

Есть ли какой-нибудь способ удалить это предупреждение?

Ответ №1:

Предупреждение касается массива VNode s, созданного в setup() функции визуализации «s Composite.js «.

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

Это неэффективно, поскольку дочерний слот отображается еще до HelloWorld того, как компонент сможет его использовать. Дочерний слот по существу отображается в родительском, а затем передается дочернему. Включение генерации дочернего слота в функцию откладывает выполнение работы до тех пор, пока дочерний элемент не будет отрисован.

Я не понимаю, в чем разница, если я использую слоты из шаблона или из другого компонента.

@vue/compiler-sfc компилирует <template> из SFCs в функцию визуализации, где слоты передаются как функции, что позволяет избежать предупреждения, которое вы наблюдали.

Решение

Вместо того, чтобы отображать дочерний слот в родительском (т. Е. Напрямую передавать массив VNodes в качестве slots аргумента), оберните его в функцию:

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

Обратите внимание, что внутренним h() вызовам не нужна эта оболочка функции, потому что все они отображаются вместе со слотом по умолчанию.

ДЕМОНСТРАЦИЯ