再現方法
親子関係のcomponentsにおいて、子から親にemit
すること
警告の内容
[Vue warn]: Extraneous non-emits event listeners (rewrite) 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. at ...
コンポーネントがフラグメントまたはテキストのルートノードをレンダリングするため、外部の非エミッツイベントリスナー(書き換え)がコンポーネントに渡されましたが、自動的に継承することができませんでした。
リスナーがコンポーネントのカスタムイベントリスナーのみを意図している場合は、"emits "オプションを使用して宣言してください。
[翻訳] DeepL
結論
子(emitする側)のコンポーネントでemits
オプションを定義した上で、emit名を配列で宣言する。
以下のESLintルールに詳しい。
https://eslint.vuejs.org/rules/require-explicit-emits.html
このルールが追加された背景としてはコンポーネントからどんなイベントがemitされるのかを構造的に宣言できるようにすることでコードの自己文書化をしよう!みたいな意図だと理解した。
詳細なコード
親で定義したmsg
変数を子のinputタグで書き換える単純なprops down, emits upの構成
親コンポーネント
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld :msg="msg" @rewrite="changeMsg" />
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
export default defineComponent({
name: 'App',
components: {
HelloWorld,
},
setup() {
let msg = ref('Hello Vue 3.0 + Vite')
const changeMsg = (e) => {
msg.value = e.target.value
}
return {
msg,
changeMsg,
}
},
})
</script>
子コンポーネント
<template>
<h1>{{ msg }}</h1>
<button @click="count++">count is: {{ count }}</button>
<p>
Edit <code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
<input type="text" :value="msg" @input="changeMsg" />
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
type Props = {
msg: string
}
export default defineComponent({
name: 'HelloWorld',
props: {
msg: {
type: String,
default: 'default Value',
},
},
emits: ['rewrite'], // このオプションが必要
setup(props: Props, { emit }) {
const count = ref(0)
const changeMsg = (e) => {
emit('rewrite', e)
}
return {
count,
changeMsg,
}
},
})
</script>
何が詰まったか
- emitsオプションを定義すべきことは分かるが、どういった形式で宣言すべきか、また何を宣言すべきかのヒントが無い
- 警告内容でググっても現時点ではこのルールそのもののPRしかヒットせず、どうすれば解決するかが掴めない(https://github.com/vuejs/vue-next/issues/1001)
- 純粋にググラビリティが低く、
vue 3 emits option
等検索しても2.x時代のドキュメントが大量にヒットしてしまう
というわけで
謎に詰まってしまった。。。
おもむろに親子間でemitするだけで警告されるので、2.x時代からVueを書いている方はお気をつけください。