【Nuxt3】値を監視する場合v-ifの判定にはnullとundefinedを両方判定に使おう

運営者:そうすけ

愛媛在住のエンジニア兼ブロガー。
工場勤務から社内SEにキャリアチェンジ。
主に社内向けのシステム開発を行っています。

【ブログ運営歴】2021.6~
【プログラミング歴】2022.3~

本業:Java,MySQL、個人:Javascript

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のライフサイクルまで踏み込めばもっと理解が深まりそうです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

目次