【Vue 3】コンポーネント間のデータの受渡し【基礎】


1. はじめに  

1-1. はじめに

Vueのコンポーネント間のデータの受渡しが「親→子」「子→親」で異なり複雑です。
私の頭を整理するために、この記事を記載しています。

1-2. 説明の前に・・・

説明で使用するプログラム ( x.html, x.js ) は、下記の.htmlファイルに記載する前提での説明です。
また、記載はVue3ですが、基本的にVue2でも同じ考え方です。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://unpkg.com/vue@next"></script>
  <title>vue sample</title>
</head>
<body>
  <div id="app">
      // **************************************
      // ここにx.htmlを記載
      // **************************************
  </div>
  <script>
      // **************************************
      // ここにx.jsを記載
      // **************************************
  </script>
</body>
</html>

2. コンポーネントの基礎

2-1. コンポーネントとは

コンポーネントは「名前付きの再利用可能なインスタンス」です。
2-1.jsのようにコンポーネントを定義し、2-1.htmlで定義したコンポーネントを3つ使用しています。
コンポーネントが再利用され、3つのボタンが表示されます。

2-1.html
<div id="app">
  <Counter></Counter>
  <Counter></Counter>
  <Counter></Counter>
</div>
2-1.js
// アプリケーションの生成
const app = Vue.createApp({})

// コンポーネントを定義 (第一引数:コンポーネントの名前, 第二引数:コンポーネントオブジェクト)
app.component('Counter',{
  data() {
    return {
      count : 0
    }
  },
  template: `
    <button v-on:click="count++"> コンポーネントだよ:{{count}} </button>
  `
})

// id="app" にマウント
app.mount('#app')

2.2 グローバルコンポーネントとローカルコンポーネント

コンポーネントには2種類あります。グローバルコンポーネントローカルコンポーネントです。

  • グローバルコンポーネント
    アプリケーションのcomponentメソッドを利用します。
    アプリケーション内のどのコンポーネントのテンプレートでも使用できます。
    2-1で定義したコンポーネントもグローバルコンポーネントです。
    実際はビルドの最適化を高めるために、ローカルコンポーネントで定義するほうが一般的です。   

  • ローカルコンポーネント
    オブジェクトを定義して、componentsオプションで登録します。 
    componentsで登録したコンポーネント内でのみ使用できます。

以下の例は、ローカルコンポーネントChildをグローバルコンポーネントParentcomponentsに登録しています。
Parentの中でのみChildが使用できるようになります。
この際、Parent親コンポーネント(以降、親)、Child子コンポーネント(以降、子)といいます。1

2-2.html
<div id="app">
  <Parent></Parent>
</div>
2-2.js
// アプリケーションの生成
const app = Vue.createApp({})

// ローカルコンポーネント+子コンポーネント
// オブジェクトを定義
const Child = {
  template: `
    <h2> Child ! </h2>
  `
}

// グローバルコンポーネント+親コンポーネント
app.component('Parent',{
  // コンポーネントの登録をする
  components: {
    Child
  },
  // 親コンポーネントの中で子コンポーネントは使用できる
  template: `
    <h1> Parent ! </h1>
    <Child></Child>
  `
})

// id="app" にマウント
app.mount('#app')

3. コンポーネント間のデータの受渡しの基礎

3-1. 親コンポーネントから子コンポーネントへのデータの受渡し

子にpropsオプションを定義します。親からデータを渡すときはhtmlの属性を使用するように渡すことができます。
基本的にVueでは親から子への単方向のデータフローです。
propsの定義の仕方を変えると、バリデーションも付けられます。

3-1.html
  <div id="app">
    <Parent></Parent>
  </div>
3-1.js
// アプリケーションの生成
const app = Vue.createApp({})

// 子コンポーネント
const Child = {
  // 親から受け取るdataを定義
  props:['parentData'],
  template: `
    <h2> Child ! </h2>
    <h2> {{parentData}} </h2>
  `
}

// 親コンポーネント
app.component('Parent',{
  components: {
    Child
  },
  // htmlの属性のように記載してデータを渡す
  template: `
    <h1> Parent ! </h1>
    <Child parentData="親コンポーネントから書き換え!"></Child>
  `
})

3-2. 子コンポーネントから親コンポーネントへのデータの受渡し

Vueは親から子への単方向データフローです。そのため、子から親へデータを受け渡すには少し工夫が必要です。

  1. $emitを使用して、子から親のイベントを発火させます。
  2. イベントで設定されたJavaScriptやメソッドを実行させ、その中で親のデータを変更します。
    データの受取り方法は2種類あります。$eventを使用する方法とメソッドの第一引数で受け取る方法です。
3-2.html
  <div id="app">
    <Parent></Parent>
  </div>
3-2.js
const app = Vue.createApp({})

// 子コンポーネント
const Child = {
  // $emitの第一引数はイベント名(childData)、第二引数は渡す値("親に渡すデータ")を定義
  template: `
    <button v-on:click='$emit("childData","親へ渡すデータ")'>親へデータ渡すボタン</button>
  `
}

// 親コンポーネント
app.component('Parent',{
  data() {
    return {
      eventData: '',  // $eventで渡したデータを格納
      methodData: '', // メソッドで渡したデータを格納
    }
  },
  components: {
    Child
  },
  // $eventを使用する方法とメソッドで渡す方法がある
  template: `
    <h1> Parent ! </h1>

    <h3>1. $eventを使用する方法</h3>
    <Child v-on:childData="eventData = $event"></Child>
    eventData : {{eventData}}

    <h3>2. メソッドで渡す方法</h3>
    <Child v-on:childData="changeParentData"></Child>
    methodData : {{methodData}}
  `,
  methods: {
    // methodの第一引数としてデータが渡される
    changeParentData(event) {
      this.methodData = event 
    }
  }
})

// id="app" にマウント
app.mount('#app')

4. おわりに

最後まで読んでいただきありがとうございました。今回の記事のポイントは以下です。

  • Vueは親コンポーネントから子コンポーネントへの単一方向のデータフローである。
  • 親→子:子でpropsを用いてデータを受け取る。
  • 子→親:子にて$emitを使用してイベントを起動。親にて$eventやメソッドでデータを受け取る。

記載の誤りや、文字の揺らぎがあるかもしれません。ご指摘がありましたらコメントいただけると幸いです。
詳細が知りたい方や、より正確な情報を知りたい方は参考URL(Vue3公式ページ)を参照してください。

参考URL


  1. 親はグローバルコンポーネント、子はローカルコンポーネントというルールはありません。componentsオプションを定義しているのが親、定義に使用されているのが子です。