運営者:そうすけ
愛媛出身の30代のブロガー兼ソフトウェアエンジニア。
主にフロント・バックの開発を行っています。
趣味はガジェットと植物。
APIの結果が帰ってきてから描画したい要素をv-ifで判定するとします。
その場合、nullとundefinedを使うとうまく表示されました。
<div v-if="review.rating !== null && review.rating !== undefined">
APIで取得したよ
</div>
この判定を利用するときって?
たとえば、モジュールを使っていて、そのコンポーネントのpropsが双方向データバインディングになっていない場合です。
この場合だと、一度受け取った引数は二度と演算されず、初期値のみは反映されます。
非同期処理は基本的に描画の後なので、せっかく値を取得してきても入れることができません。
Nuxt-ratingを使用するときに発生した
下記のような評価の星を扱うモジュールです。
propsの初期値を一度設定したらリアクティブに反映されないモジュールでした。
<NuxtRating
:read-only="true"
:rating-count="5.0"
:rating-size="'32px'"
:rating-value="5"
/>
raring-valueにpropsを指定すると値を反映した星の数を反映してくれます。
ただしpropsを判定してくれるのは初期に渡した値のみです。
type Props = {
ratingCount?: number
...
ratingValue?: number
}
const props = withDefaults(defineProps<Props>(), {
ratingCount: 5,
...
ratingValue: 3.7,
})
モジュールを改造してもいいのですが、コンテナ内にnpm_modeleを入れており、なんとか工夫できないかと考えておりました。
値の挙動を整理する
データの流れを整理してみました
- まず描画される
- JSが実行され変数が初期化される
- 非同期処理が実行され、値が格納される
これをもとにv-ifに設定した変数の値を考えてみます。
- 描画されるときはJSが実行されてないので「undefind」
- JSが実行され初期値が宣言されるので「null」
- 非同期処理が完了して値が入る
こうすると、値がundefined→null→取得した値を言う風に値がなっていきます。
成功例と悪い例
これをもとに私の例を示します。
悪い例
v-ifの判定がnullのみで先にレンダリングさせてしまっています。
<div v-if="review.rating !== null>
<NuxtRating
:read-only="true"
:rating-count="5.0"
:rating-size="'32px'"
:rating-value="review.rating"
/>
</div>
<script setup lang="ts">
const rating = ref(null);
onMounted(() => {
const getReview = async() => {
try {
const response = await useGet(`/api/v1/reviews/${reviewID}`,customHeaders);
rating.value = response.rating
} catch (error) {
console.log(error)
}
}
async function getReviewFunc(){
await getReview()
}
getReviewFunc()
})
</script>
評価の値が2であるのに対して、星の値がモジュールの指定した初期値のままです。
成功例
nullを初期値に入れていても、先にレンダリングされるので
<div v-if="review.rating !== null && review.rating !== undefined">
<NuxtRating
:read-only="true"
:rating-count="5.0"
:rating-size="'32px'"
:rating-value="review.rating"
/>
</div>
<script setup lang="ts">
const rating = ref(null);
onMounted(() => {
const getReview = async() => {
try {
const response = await useGet(`/api/v1/reviews/${reviewID}`,customHeaders);
rating.value = response.rating
} catch (error) {
console.log(error)
}
}
async function getReviewFunc(){
await getReview()
}
getReviewFunc()
})
</script>
反映されました!
まとめ
まれなケースかもしれませんが、意外と詰まりました。
描画のタイミングなど、特にSSRのNuxtだとかなり重要になってくるので、VUEのライフサイクルまで踏み込めばもっと理解が深まりそうです。
コメント