コンポーネント化 パート2

コンポーネント間のデータの受け渡し

Vue コンポーネント間でデータを受け渡しする基本的な方法として、propsemit を使用します。

Props

親コンポーネントから子コンポーネントにデータを渡すための方法です。

まずは子コンポーネント側で defineProps マクロを使用し、受け取りたいデータを定義します。

<!-- Child.vue -->
<script setup lang="ts">
defineProps<{ message: string }>()
</script>

次に親コンポーネント側で、子コンポーネントにデータを渡すために v-bind ディレクティブを使用します。
:props名="データ" という形式で、子コンポーネントにデータを渡すことができます。

<!-- Parent.vue -->
<template>
  <Child :message="message" />
</template>

また、props 名とデータの変数名が同名の場合は省略記法を使うことができます。

<!-- Parent.vue -->
<template>
  <Child :message />
</template>

Emit

子コンポーネントから親コンポーネントにイベントを発火するための方法です。

まずは子コンポーネント側で defineEmits マクロを使用し、発火したいイベントを定義します。 emit 関数を用いて、イベントを発火することができます。

<!-- Child.vue -->
<script setup lang="ts">
const emit = defineEmits<{ sendMessage: [] }>()
</script>

<template>
  <button type="button" @click="emit('sendMessage')">
    Click me
  </button>
</template>

発火されたイベントは親コンポーネント側で v-on ディレクティブを使用して受け取ることができます。

<!-- Parent.vue -->
<script setup lang="ts">
function handleSendMessage() {
  console.log('Message sent!')
}
</script>

<template>
  <Child @send-message="handleSendMessage" />
</template>

以下のように、イベント発火時に子コンポーネントからデータを受け渡すこともできます。

<!-- Child.vue -->
<script setup lang="ts">
const emit = defineEmits<{ sendMessage: [string] }>()
</script>

<template>
  <button type="button" @click="emit('sendMessage', 'Hello, Vue!')">
    Click me
  </button>
</template>
<!-- Parent.vue -->
<script setup lang="ts">
function handleSendMessage(message: string) {
  console.log(message) // Hello, Vue!
}
</script>

<template>
  <Child @send-message="handleSendMessage" />
</template>

それぞれの詳しい API ドキュメントから確認することができます。

現在の実装の課題

app.vueに定義されたtodosにTodoList.vueからアクセスすることができていません。 propsemit を使用して、コンポーネント間でデータをやり取りできるようにしましょう。

チャレンジ2

propsemit を使用して親子間でデータの受け渡しをできるようにしましょう:

  1. TodoList.vuedefinePropsを使用して親からtodosを受け取れるようにしましょう
  2. app.vue<TodoList />を配置して、todosを渡してみましょう。
  3. TodoList.vuedefineEmitsを使用してアイコンのクリックイベントを親に伝えられるようにしましょう
  4. app.vueTodoList.vueから受け取ったイベントを利用してupdateDoneを実行しましょう

参考実装:

<script setup lang="ts">
/**
 * Props
 */
defineProps<{
  todos: Todo[]
}>()

/*
 * Emit
 */
const emit = defineEmits<{
  updateDone: [number, boolean]
}>()
</script>

実装後の効果

コンポーネント化すると:

  • 関心ごと(表示とロジック)が分割され、コードの見通しが良くなる
  • 複数のコンポーネントで同じUIパーツを再利用できるようになる
  • 親子間のデータ受け渡し(props・emit)を通じて状態管理が整理され、チーム開発や拡張がしやすくなる

もし行き詰まったら、以下のボタンをクリックして解答を見ることができます。

コンポーネント化され、メンテナンスしやすいスッキリした構造になりました!

コンポーネント化 パート1
Vue.js のコンポーネントは、UI を小さな再利用可能な部分に分割するための基本的な単位です。 特に Single File Components (SFC) を使うことで、HTML、CSS、および JavaScript を 1 つの .vue ファイルにまとめることができます。
双方向データバインディング
Vueでは v-model ディレクティブを使うことで、フォーム要素やカスタムコンポーネントと「双方向データバインディング」を簡潔に実現できます。ユーザーの入力とVueのデータが常に同期され、フォーム制御が直感的になります。
ファイル
エディタ
WebContainerを初期化中
ファイルをマウント中
依存関係をインストール中
Nuxtサーバーを起動中
Nuxtが準備完了を待機中
ターミナル