Vue.js 開発中に学んだリアクティブデータとコンポーネント間の通信
Vue.js を使った開発では、リアクティブデータの管理やコンポーネント間の通信が重要な要素となります。本記事では、Vue.js の v-model
、emit
、props
の使い方を中心に、実際に経験したトラブルシューティングとその解決方法を紹介します。
問題の背景: 親子間でのデータの同期がうまくいかない
あるプロジェクトで、親コンポーネントから子コンポーネントにデータを渡し、さらに子コンポーネントで編集したデータを親に戻す必要がありました。以下のようなコードで、aliasImg
と aliasName
を管理しようとしました。
親コンポーネント
<template>
<input type="text" v-model="aliasName" placeholder="グループ中の自分の名前">
<PeopleImg v-model="aliasImg" />
<button @click="join">▶️</button><br>
</template>
<script setup>
import { ref } from "vue";
import PeopleImg from "./PeopleImg.vue";
const aliasName = ref("");
const aliasImg = ref("");
async function join() {
console.log(aliasImg.value);
if (!confirm("実行▶️")) {
return;
}
}
</script>
子コンポーネント
const props = defineProps({
alias: Object,
modelValue: String,
});
const emit = defineEmits(["update:modelValue"]);
const registerCombination = () => {
aliasImg.value = "emoji, color";
emit("update:modelValue", aliasImg.value); // 親にデータを通知
};
問題の発生
子コンポーネントでデータが更新されても、親コンポーネント側の aliasImg
に反映されませんでした。console.log
で確認すると、子では値が存在するのに親には渡っていません。
解決方法
1. emit
の定義がない場合
子コンポーネントで defineEmits
が定義されていないと、親にデータを送ることができません。このコードでは defineEmits
を使って update:modelValue
イベントを明示的に定義します。
const emit = defineEmits(["update:modelValue"]);
2. registerCombination
のトリガーがない
データの更新が行われる関数が親コンポーネントから呼び出されないと、emit
が発火しません。以下のようにトリガーを確実に動かす必要があります。
<button @click="registerCombination">Update</button>
複数の v-model
を使う場合
Vue 3 では複数の v-model
を使うことができます。その場合、それぞれの v-model
にプロパティ名を指定する必要があります。
親コンポーネント
<template>
<PeopleImg v-model:alias="aliasImg" v-model:other="otherValue" />
</template>
<script setup>
import { ref } from "vue";
import PeopleImg from "./PeopleImg.vue";
const aliasImg = ref("");
const otherValue = ref("");
</script>
子コンポーネント
const props = defineProps({
alias: String,
other: String,
});
const emit = defineEmits(["update:alias", "update:other"]);
const updateAlias = (value) => {
emit("update:alias", value);
};
const updateOther = (value) => {
emit("update:other", value);
};
IndexedDB との連携とエラー処理
開発中にブラウザ拡張機能 IndexedDBedit
が原因で、IndexedDB のデータが破損していることに気付きました。IndexedDB にアクセスする際には、適切なエラーハンドリングが重要です。
IndexedDB のアクセス例
async function getIDB(table, id) {
try {
const db = await openDatabase();
const transaction = db.transaction([table], "readonly");
const objectStore = transaction.objectStore(table);
const getRequest = objectStore.get(id);
return new Promise((resolve, reject) => {
getRequest.onsuccess = (event) => {
const data = event.target.result;
data ? resolve(data) : reject(new Error(`${table} by ${id} not found`));
};
getRequest.onerror = (event) => {
reject(new Error(`Error getting data: ${event.target.error}`));
};
});
} catch (error) {
console.error("Error in getIDB:", error);
throw error;
}
}
学びとベストプラクティス
-
v-model
の正しい設定:- 子コンポーネントで
emit
を適切に定義。 - 親から渡されたデータを常にリアクティブにする。
- 子コンポーネントで
-
非同期処理とエラーハンドリング:
- IndexedDB など非同期データを扱う際は、エラーハンドリングを徹底。
- ブラウザの拡張機能による影響を考慮する。
-
複数の
v-model
:- 名前付きの
v-model
を活用して、複数のデータを管理する。
- 名前付きの
まとめ
Vue.js を使った開発では、親子間のデータ同期やリアクティブデータの管理が重要です。本記事で紹介したテクニックや解決方法を活用すれば、より効率的な開発ができるでしょう。皆さんもぜひ試してみてください! 🎉
いかがでしょうか?必要に応じて調整もできますので、フィードバックがあれば教えてください! 😊
登録日:
更新日: