Vue 3における以下の警告について原因と解決策を提示する。

Extraneous non-emits event listeners (emitFunc) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the “emits” option.

警告の内容と原因

内容

runtime-core.esm-bundler.js:38 [Vue warn]: Extraneous non-emits event listeners (emitFunc) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option. 

この警告は、特定のカスタムイベントリスナ(このケースではemitFunc)がコンポーネントに渡されているが、それらが自動的に継承できないと言っている。

原因

「自動的に継承できない」という状況は主に、コンポーネントが「複数のルート要素またはテキストをルートノードとしてレンダリングする場合」に発生する。

以下のような構成。今回、この構成が問題だった。

<template>
 <custom-primary-component @emitFunc="emitFunc" />
 <custom-secondary-component />
</template>

この警告が発生する主な原因は、Vue.js 3ではフラグメント(複数のルート要素)を持つことが許されているためである。しかし、複数のルート要素がある場合、どの要素にイベントリスナーを適用すればいいのかが曖昧になるため、このような警告が発生する。

参照(Vue 3 移行ガイド): Fragments

解決策

方法は2つある。

  1. イベントをemitsオプションで明示的に宣言する
  2. 単一のルート要素を持つようにコンポーネントをリファクタリングする

1. イベントをemitsオプションで明示的に宣言する

emitsオプションでイベントを宣言することで、Vue.jsにこのイベントがカスタムイベントであると明示的に伝え、警告を消すことができる。

<template>
 <custom-primary-component @emitFunc="emitFunc" />
 <custom-secondary-component />
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  // emitsオプションで明示的に宣言する
 emits: ['emitFunc'],
  components: {
    CustomPrimaryComponent,
    CustomSecondaryComponent 
  },
})
</script>

参照: emits

setup構文の場合は以下のように書ける。

<script setup>
defineEmits(['emitFunc'])
</script>

参照: defineProps() & defineEmits()

2. 単一のルート要素を持つようにコンポーネントをリファクタリングする

<template>
 <div class="single-root">
   <custom-primary-component @emitFunc="emitFunc" />
   <custom-secondary-component />
 </div>
</template>

このようにすると、全体がdiv.single-rootという1つのルート要素によって囲まれ、問題が解決される可能性がある。これで、任意のイベントリスナやプロパティがこの単一のルート要素に適用される。

カテゴリー: Vue.js