Vue.jsで取得したデータをリアクティブに表示するためにref
を使用しましたが、軽くつまづいたためその原因と対処法について共有します。
“ref”の値が表示されない
今回やりたかったことは、データベースから英語フレーズのリストを取得してフレーズ一覧を表示することです。
ただ、以下の実装ではデータベースから取得したフレーズを画面に表示できませんでした。
<template>
<v-row class="px-2">
<v-col cols="12" xs="12" sm="12" md="6" lg="6" xl="6">
<v-list>
<v-list-item v-for="(item, index) in phrases" :key="index">
<v-list-item-content>
<v-list-item-title>{{ item.english }}</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list>
</v-col>
</v-row>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from "@vue/composition-api";
import { API } from "aws-amplify";
import { listPhrases } from "~/graphql/queries";
type Phrase = {
id: string;
english: string;
};
export default defineComponent({
setup() {
const phrases = ref<Phrase[]>([]);
async function fetchAllPhrase() {
const response = await API.graphql({
query: listPhrases,
});
// @ts-ignore
phrases = response.data.listPhrases.items as Phrase[];
}
onMounted(async () => {});
return {
fetchAllPhrase,
phrases,
};
},
});
</script>
原因と対処法
結論、setup()
内の以下の箇所が間違っていました。
phrases = response.data.listPhrases.items as Phrase[];
ref
で定義された値は.value
で読み取ってあげる必要があるようです。
以下のように修正したらデータベースから取得したフレーズがうまく表示されました。
phrases.value = response.data.listPhrases.items as Phrase[];
なぜ.value
で参照する必要があるのか。それはref
関数に渡した値が value をキーとしたオブジェクトに変換されるからのようです。以下のようなイメージ。
phrases = {
value: "ref関数に渡した値" //今回の場合、Phrase型の配列
//省略
}
ではそもそも、なぜオブジェクトに変換するのかというref
の仕組みに関しては、Vue.js 3 をつくって学ぶ リアクティブシステムの記事で丁寧に説明されていますので、気になる方はご参照ください。
なお、setup()
で返却されたオブジェクトのvalue
プロパティは直接参照される仕様のため、template
内では.value
が不要になるようです。
あとがき
ふとref
のオブジェクトは再代入不可のconst
で定義したらダメなのでは?と思いました。
しかし、const
はオブジェクト内のキーや値が変更されても再代入(新たにメモリを確保)とならず問題ないみたいですね。知りませんでした。
ただオブジェクトを丸ごと変更したり、string
やnumber
などの(オブジェクトでない)プリミティブ型の値を変更する可能性がある時は、let
で変数宣言する必要があります。
参照先を変更し再代入となる処理を行う場合、const
ではエラーになるからですね。
【JavaScript】var / let / const を本気で使い分けてみたの以下の画像が分かりやすいです。
コメント