ホーム
Sponserd by↑転職したい人向け、ベンチャー企業の採用動画があります

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

まっつんです。

世間はコロナで大騒ぎですし、どげんかせんといかんと思っていますが、まぁ自分にできることは1ヶ月後2ヵ月後に向けて一心不乱にコードを書くだけかなと思っています。

ブログを書くのは気分転換にすごく良い気がしますね。

プログラミングを書く人の気分転換って、例えば、本を読むとか、数学を解くとか、英語を覚えるとか、なんかそんなイメージです。

違うか。

最初に。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

https://poppotennis.com/laravel_vue-js_vuex/

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

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

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

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

あとは、

そいつらを、

渡していくのみ!!!

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

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

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

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

//親

: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つでも渡せます。

まとめ

確かにコードはコピペをすれば間違いなく動きます。

でも、もしその部分を書き換えたくなった時がきたら・・・。

ああ、コンポーネント化しておいてよかったなって思えると思います。

データの受け渡しはややこしいようで、親のデータを基準に考えれば意外と簡単に慣れるかもです。