Vue.jsにおける親から子へのデータ渡し(Props)

2025-07-29

Propsの基本概念とデータフロー

Vue.jsにおいて、Props(プロパティ)は親コンポーネントから子コンポーネントへデータを渡すための仕組みです。Reactや他のフレームワークにも類似の概念がありますが、VueのPropsシステムは特にシンプルで直感的に使用できるように設計されています。

Propsのデータフロー図

[親コンポーネント]
   │
   ↓ (propsとしてデータを渡す)
[子コンポーネント]

このデータフローは一方向(親→子)に限定されており、これによりアプリケーションのデータフローが予測可能で理解しやすくなります。

Propsの基本的な使い方

1. 親コンポーネントでのデータ定義

親コンポーネントでデータを定義し、子コンポーネントに渡します。

<template>
  <div>
    <!-- 子コンポーネントにmessageデータを渡す -->
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentMessage: '親からのメッセージ'
    }
  }
}
</script>

2. 子コンポーネントでのProps受け取り

子コンポーネントはpropsオプションで受け取るデータを宣言します。

<template>
  <div>
    <!-- 親から受け取ったmessageを表示 -->
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  props: ['message'] // 親からmessage propを受け取る
}
</script>

Propsの詳細設定

型指定とバリデーション

Propsには型指定やバリデーションを設定できます。

export default {
  props: {
    // 基本的な型チェック
    age: Number,

    // 複数の型を許可
    userId: [String, Number],

    // 必須フラグとデフォルト値
    username: {
      type: String,
      required: true,
      default: '匿名ユーザー'
    },

    // カスタムバリデーター
    email: {
      type: String,
      validator: value => {
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
      }
    }
  }
}

オブジェクトと配列のProps

オブジェクトや配列もpropsとして渡せます。

<!-- 親コンポーネント -->
<template>
  <ChildComponent :user-info="userData" :items="itemList" />
</template>

<script>
export default {
  data() {
    return {
      userData: {
        name: '山田太郎',
        age: 30
      },
      itemList: ['アイテム1', 'アイテム2', 'アイテム3']
    }
  }
}
</script>

<!-- 子コンポーネント -->
<script>
export default {
  props: {
    userInfo: Object,
    items: Array
  }
}
</script>

動的Props

v-bindを使って動的にpropsを渡せます。

<template>
  <div>
    <input v-model="dynamicMessage" />
    <ChildComponent :message="dynamicMessage" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      dynamicMessage: ''
    }
  }
}
</script>

命名規則とケース変換

Vueでは以下の命名規則が推奨されます:

  • JavaScript(子コンポーネント): camelCase
  • テンプレート(親コンポーネント): kebab-case
// 子コンポーネント
export default {
  props: ['userName', 'isActive']
}

// 親コンポーネント
<template>
  <ChildComponent 
    :user-name="name" 
    :is-active="active" 
  />
</template>

非Prop属性の継承

propsとして明示的に宣言されていない属性は、子コンポーネントのルート要素に自動的に適用されます。

// 親コンポーネント
<ChildComponent class="child-style" data-test="test" />

// 子コンポーネントのレンダリング結果
<div class="child-style" data-test="test">
  <!-- 子コンポーネントの内容 -->
</div>

高度なPropsパターン

複数のv-bindによるprops渡し

オブジェクトを使ってまとめてpropsを渡せます。

<template>
  <ChildComponent v-bind="userProps" />
</template>

<script>
export default {
  data() {
    return {
      userProps: {
        name: '佐藤花子',
        age: 25,
        email: 'sato@example.com'
      }
    }
  }
}
</script>

関数をpropsとして渡す

親のメソッドを子に渡すことも可能です。

<!-- 親コンポーネント -->
<template>
  <ChildComponent :formatter="formatName" />
</template>

<script>
export default {
  methods: {
    formatName(name) {
      return name.toUpperCase()
    }
  }
}
</script>

<!-- 子コンポーネント -->
<script>
export default {
  props: {
    formatter: Function
  },
  methods: {
    processName(name) {
      return this.formatter(name)
    }
  }
}
</script>

よくある間違いとベストプラクティス

1. Propsの直接変更は避ける

// 悪い例
this.message = '新しい値' // 警告が発生

// 良い例
// 親コンポーネントにイベントを発行して変更を依頼
this.$emit('update:message', '新しい値')

2. 初期値が必要な場合

export default {
  props: ['initialCount'],
  data() {
    return {
      count: this.initialCount // propsから初期値を設定
    }
  }
}

3. 複雑なオブジェクトの監視

export default {
  props: ['config'],
  watch: {
    config: {
      deep: true, // ネストされた変更も監視
      handler(newVal) {
        console.log('configが変更されました', newVal)
      }
    }
  }
}

実践的な使用例

商品カードコンポーネント

<!-- 親コンポーネント -->
<template>
  <div>
    <ProductCard
      v-for="product in products"
      :key="product.id"
      :product="product"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      products: [
        { id: 1, name: 'ノートパソコン', price: 120000, stock: 5 },
        { id: 2, name: 'スマートフォン', price: 80000, stock: 10 }
      ]
    }
  }
}
</script>

<!-- 子コンポーネント (ProductCard.vue) -->
<template>
  <div class="product-card">
    <h3>{{ product.name }}</h3>
    <p>価格: {{ product.price.toLocaleString() }}円</p>
    <p :class="{ 'low-stock': product.stock < 3 }">
      在庫: {{ product.stock }}個
    </p>
  </div>
</template>

<script>
export default {
  props: {
    product: {
      type: Object,
      required: true,
      validator: product => {
        return (
          typeof product.id === 'number' &&
          typeof product.name === 'string' &&
          product.price > 0
        )
      }
    }
  }
}
</script>

<style>
.product-card {
  border: 1px solid #ddd;
  padding: 16px;
  margin: 8px;
  border-radius: 4px;
}
.low-stock {
  color: red;
  font-weight: bold;
}
</style>

パフォーマンスに関する考慮事項

  1. 大きなオブジェクトをpropsとして渡さない
    大きなデータセットはVuexやPiniaなどの状態管理ライブラリを使用
  2. 不変なデータはv-onceで最適化
    変更されないpropsにはv-onceディレクティブを使用
<template>
  <div v-once>
    {{ staticMessage }}
  </div>
</template>
  1. 計算プロパティでpropsを変換
    複雑な変換が必要な場合
export default {
  props: ['rawDate'],
  computed: {
    formattedDate() {
      return new Date(this.rawDate).toLocaleDateString()
    }
  }
}

まとめ

  • Propsは親から子への一方向データフロー
  • 型チェックとバリデーションで堅牢なコンポーネントを作成
  • 命名規則(camelCase/kebab-case)を遵守
  • Propsの直接変更は避け、イベント発行で親に変更を依頼
  • 複雑なデータにはオブジェクトや配列を使用可能
  • パフォーマンスを考慮したprops設計が重要

このガイドでVue.jsのpropsシステムの基本から実践的な使い方までを網羅的に理解できたはずです。propsを適切に使用することで、コンポーネント間のデータフローを明確にし、保守性の高いアプリケーションを構築できます。