Vue

【Vue】親コンポーネントのデータを子コンポーネントで変化させる方法【emit】

いつもご利用ありがとうございます。このブログは、広告費によって運営されています。

オススメ本
Web技術を勉強するなら、かなりオススメの雑誌です。毎月新しい発見があります。ついに最終号・・・、みなさん買いましょう!!
読んで損することはない名著。命名で悩むことが多い人はこの本がオススメです。

⇨ Vue 記事の目次はこちら

Vue で emit を使って、親コンポーネントのデータを子コンポーネントから変化させる方法について、記事にしました。

結論から

親コンポーネント

<ChildrenComponent @morota='watasuyatu'/>

methods: {
  watasuyatu: function(){
    console.log('a');
  }
}

子コンポーネント

methods: {
morotayatu() {
  //@morotaなので、morotaという名前でemitできる
   this.emit('morota');
  }
}

最初に。

まず、感覚は人それぞれなのですが、この記事に関しては「僕の」感覚で、これだと分かりにくかった、やりにくかったという話なので World Standard な話しではないと思っていただければと思います。

コンポーネント化はいつするか

プロジェクトが中盤や終盤になってくると、1ページでほとんどがコンポーネント化されたりします。

ただ、コンポーネント化は普通に考えて手間です。

「別ファイルを作って、import する?あああ相対パス間違ってるー。ファイル名が違う?コンポーネント登録してない!props の名前間違えた!型が違う!」

誰もが通る道だと思います。

コンポーネント化をするべきタイミングはこんなときだと思います。

① 全く同じ部品を作ることになった

② 同じページを分担して作成する

③ マジで CSS が長くてオシャレなボタン作った(コードが長い)

こんなときなんじゃないかなぁと思います。

逆に言えばこういうときは、積極的にコンポーネント化を図る「べき」だと思います。

理由はその後、確実に楽だからです。

ちょっとしたエラーが見つかったとき、1箇所直せば全部安全に直るというのはマジで良い。

ただ、このとき懸念が出てきます。

「データのやり取りややこし丸問題」

Vuex の記事

自分が以前書いた記事では Vuex でこの問題解決について書いてますが今回は emit で行ってみます。

まず、親コンポーネントで全部書いてしまえばよい

データを親コンポーネントで受け取っておいて、

そのデータをどういう変化させたいのかを、親コンポーネントに全部書いてしまえば丸く収まります。

あとは、

そいつらを、

渡していくのみ!!!

親コンポーネントで作った methods を子コンポーネントに渡すときに emit を使う

最初、「監視」してるというのは自分にはすごく分かりづらかったのですが、「methods」を受け渡しているって考えても動きます。

実際に動いているのは親のメソッドなので、親のデータを変えることが出来て、そのデータに関連した場所の表示が勝手に変わってくれるということですね。

例えば props では v-bind を使って

⇨Vue の Props の使い方と基本的な書き方

//親

:props='watasuyatu'

などとしていたところを、emit の場合は

//親

@morota='watasuyatu'

という風に@にするだけ!

それに対して、

//子

methods: {
morotayatu() {
   this.emit('morota');
  }
}

これで OK です。

子では、morotayatu()というメソッドで使えるようになりました。

マジで。これだけ。

emit で子からデータを引数で渡したい

実戦で使うとなると、子から親へ渡したデータを使いつつメソッドを発動したい場合もあります。

具体的には、ファイルの一覧コンポーネントを作って、ファイルをクリックするとファイルの ID を set するというものです。

もちろんファイル一覧コンポーネントでも、アップロードできるようにします。

ワードプレスみたいな感じですね。

親 methods

//動画をアップロードしたらファイルの一覧に今アップしたやつを入れたい(降順)

    addFile: function(id) {
      this.current_files.unshift(id);
    },
//ファイル選択を外した(プレビューも表示)
    removeFile: function(id) {
      this.setfile = "";
      this.preview_setfile = "";
    },

//ファイル選択した(プレビューも外す)
    setFile: function(id, image) {
      this.setfile = id; //idを最終的にDBに保存させる
      this.preview_setfile = image; //URLを入れてプレビューさせる
    },

//親テンプレート(インポートなど忘れないでねー)

 <FileModalComponent
    @addFile="addFile"
    @set="setFile"
    @remove="removeFile"
 />

//子

setNumber:function(id, image) {
this.$emit("set", id); //引数でIDを渡している @set親から来てる
this.preview = image;
},
removeNumber:function(id) {
this.$emit("remove", id); //引数でIDを渡している @remove
this.preview="";
},

 movieSelected: function(e) {
      this.movieInfo = e.target.files[0];
      let formData = new FormData();
      formData.append("movie", this.movieInfo);
      this.loading_message = "アップロード中です";
      this.loading = true;
      let config = {
        headers: {
          "content-type": "multipart/form-data"
        }
      };
      axios
        .post("/creator/upload/movie", formData, config)
        .then(res => {
          this.$emit("addFile", res.data.response); //引数でIDを渡してる @addFile
          this.loading = false;
          this.snackbar = true;
          this.message = "アップロードに成功しました";
        })
        .catch(err => {
          this.loading = false;
          this.snackbar = true;
          this.message = "アップロードに失敗しました";
        });
    }

こんな感じで引数で数字でも文字列(今回は、画像の URL)でも好きに飛ばせますし、引数は2つでも3つでも渡せます。

まとめ

以上です。

苦情や感想などあれば TwitterDM からご連絡くださいませ!

それでは!!