【vue】 emitで子から親のメソッドを実行するには

emitは、子のコンポーネントから親へ情報を伝えるための手段です。主に親のメソッドを呼び出すのに利用します。カスタムイベントとも言います。

使い方

親は、子がemitするための情報を渡します。子は、その情報に合わせてemitを実行します。

<!-- 子でthis.$emit("update-value", 渡したい値);を呼ぶと、親でsetValueが呼ばれる -->
<button-component @update-value="setValue"></button-component>
const app = Vue.createApp({
    data() {
        return {
            value: 0
        };
    },
    methods: {
        setValue(event) {
            this.value = event;
        }
    }
});
  
app.component("button-component", {
    data() {
        return {};
    },
    methods: {
        update() {
            // 親のHTMLで設定されたメソッドを呼び出す
            this.$emit("update-value", Math.random());
        }
    },
    template: `
<div>
    <button @click="update">親の値更新!</button>
</div>
`
});

See the Pen vue emit by Totori (@souki202) on CodePen.

このemitの流れはこうです。少し長いですが頑張って追っていきましょう。

emitの流れ
  1. ボタンをクリックすると、@clickに書いたメソッドが走る
    • 他のコンポーネントのメソッドは呼び出せません。自分のコンポーネントのものだけ呼べます
  2. update内で、this.$emitを通して親で指定したイベントを呼ぶ
    • 親のHTMLで@update-valueとしたら、子ではthis.$emit("update-value", ...)とします。
    • $emitの第2引数には、伝えたい値を入れます。
  3. @update-valueで指定したものが実行される。ここではsetValueを指定しているので、それが呼ばれる
    • メソッド本体を指定すると第1引数にはイベントが入ります。このイベントは、$emitの第2引数に入れたものです。
  4. 親にあるsetValueが走る

説明で区別しやすくするため、意図的にsetValueupdate-valueを分けています。

つまり、親のHTMLでemit対象とemitするための名前を指定し、子ではその名前を利用して呼び出します。

データを複数渡したい場合、連想配列にして渡す必要があります。

this.$emit("...", {hoge: 100, fuga: "foo"});

emitの宣言

コンポーネントでは、どんなemitに対応するかを書けます。

app.component("button-component", {
    data() {
        return {}
    },
    emits: ["update-value"],
    // ...
});

書かなくても動作はしますが、どんなemitが欲しいのかがわかりやすくなり、エディタ上では入力補完が効くようになるため、打ち間違いなどのミスの減少にも役立ちます。

emitのバリデーション

emitに設定したものを動作させる際には、値が正しいかのバリデーションを行うことが一応可能です。

app.component("button-component", {
    data() {
        return {}
    },
    emits: {
        "update-value": function (value) {
            // valueが0.5未満だったらemit中断
            if (value < 0.5) {
                return false;
            }
            return true;
        }
    },
    methods: {
        update() {
            this.$emit("update-value", Math.random());
        }
    },
    template: `
<div>
    <button @click="update">親の値更新!</button>
</div>
`
});

しかし、バリデーションを行う部分でのthisは、function、アロー関数共にコンポーネントではなくwindowを指し、this.$emitの戻り値も成功失敗関わらずundefinedなため、あまり役立ちません。普通に別でバリデーション用のメソッドをmethodsに入れて走らせるほうが得策です。

まとめ

emitを使用することで、子から親に向かってメソッドを実行できます。

普通のクラス設計では、クラスの双方向参照は避けられます。vueでもemitは分かりづらい動きであり、出番は減らしたいところです。

また、emitを応用し、v-modelを使って子から親に値を送信する方法があります。

vue emit thumb

役に立ったらシェアしよう!