Help us understand the problem. What is going on with this article?

Vue.jsでコンポーネントの親子間でデータのやり取りを行う方法

More than 1 year has passed since last update.

最近Vue.jsを使ったプロジェクトに手を出しています。
そこでコンポーネント間で値をやり取りする方法を調べていましたが、
こうするべきでしょ、というのを私なりに探っていった結果をまとめました。

こちらのコードの例で使用しているVueのバージョンは2.5.21です。

親から子に単方向でやり取りする方法

親コンポーネントから子コンポーネントに一方的にデータの値を渡して、
子からはそれを変更しても、親に変更は伝搬させない場合のやり方です。

シンプルにpropsに渡す

propsで親のもつ値を渡します。Vueを使うなら普通のやり方ですね。

See the Pen vue component test parent -&rt; child by stoba (@rhistoba) on CodePen.

子から親に単方向でやり取りする方法

子コンポーネントのもつデータの変更を、親コンポーネントに一方的に伝搬させる方法です。

$emitを使う

子コンポーネントでthis.$emitを実行すると、値の変更があったことをイベントとして値とともに親に知らせることができます。
親はそのイベントがトリガされた場合の処理をmethodsに書きます。

See the Pen vue component test parent <- child by stoba (@rhistoba) on CodePen.

(好ましくない例)$parentで親のプロパティを参照する

子コンポーネントでthis.$parentを使って親コンポーネントのデータを参照して、そこに直接値を代入する方法です。
しかし、これは親がデータとして何を持つべきかを子が縛ることになるので、使わない方がいいでしょう。

See the Pen vue component test parent <- child bad case by stoba (@rhistoba) on CodePen.

親子で双方向にやり取りする方法

親子両方からの変更に対して、双方ともにデータの変更を伝搬させる方法です。

(不可能な例)子のpropsの値を直接変更する

子のpropsにある、親から渡されたデータを直接変更すればよさそうに思えますが、不可能です。
propsの子からの変更は親に対して変更を与えません。
参考: https://jp.vuejs.org/v2/guide/components-props.html#%E5%8D%98%E6%96%B9%E5%90%91%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%95%E3%83%AD%E3%83%BC

See the Pen vue component test parent <-&rt; child bad case 1 by stoba (@rhistoba) on CodePen.

(好ましくない例)$parentを使う

前述の$parentを使って親のデータを直接参照する方法です。
実現こそ可能でコード量こそ少なくて済みますが、前述通り親のデータを子が縛ることになるので、
使わない方がいいでしょう。

See the Pen vue component test parent <-&rt; child bad case $parent by stoba (@rhistoba) on CodePen.

propsで親のデータを受け取り、$emitで変更をトリガする

前述の単方向のやり方を組み合わせた方法です。
冗長な感じに思えますが、親子間の双方向のやり取りはこれが基本となると思います。

See the Pen vue component test parent <-&rt; child by stoba (@rhistoba) on CodePen.

v-modelを使う

v-modelディレクティブを使うことで、上の冗長な感じをある程度改善することができます。
親側で子コンポーネントを使用する際、v-model="message"と記述することで、
:value="message" @input="message = $event"と同義になります。
そのため、子コンポーネントでプロパティにvalueを指定して、$emit('input')でイベントを送出することで、
親側で子のプロパティ変更のイベントに対する処理を記述する必要が無くなり、コンポーネントが再利用しやすくなります。
参考: https://jp.vuejs.org/v2/guide/components.html#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%A7-v-model-%E3%82%92%E4%BD%BF%E3%81%86

ただし、子コンポーネントのプロパティで使う名前が強制的にvalueになってしまうため、
これにエイリアスを与えてどのような値であるかを明示的にしたいですね。
そのため、computedで単純にvalueを返すgetterメソッドを用意するようにしましょう。

双方向のやり取りは、このやり方が最も実用的ではないでしょうか。

See the Pen vue component test parent <-&rt; child v-model bad case by stoba (@rhistoba) on CodePen.

まとめ

以上、Vueで親子コンポーネントでデータの値をやり取りする方法でした。
重要なのは、変更の処理($emit)と参照(computedなど)を切り分けて明確に行うことだと考えます。
これはReduxVuexといったfluxアーキテクチャでも同様な考えが含まれますが、
Vue単体でもそれを考慮したプログラミングが必要だと思います。

rhistoba
膝に金具が入っていたWebエンジニア
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした