Vue 3 Composition API “ref”の値が表示されない問題に対処する

技術メモ

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オブジェクト内のキーや値が変更されても再代入(新たにメモリを確保)とならず問題ないみたいですね。知りませんでした。

ただオブジェクトを丸ごと変更したり、stringnumberなどの(オブジェクトでない)プリミティブ型の値を変更する可能性がある時は、letで変数宣言する必要があります。

参照先を変更し再代入となる処理を行う場合、constではエラーになるからですね。

【JavaScript】var / let / const を本気で使い分けてみたの以下の画像が分かりやすいです。

Web 1920 – 2.png

コメント

タイトルとURLをコピーしました