web-dev-qa-db-ja.com

Vue.js:状態が変化してもデータが更新されないため、再レンダリングは行われません

Video.jsビデオプレーヤーである再利用可能なコンポーネントがあります。このコンポーネントは、データが初期DOMロードで渡されるときに正常に機能します。

Vuexで状態が更新された後、コンポーネントが再レンダリングされない理由を把握する必要があります。

親コンポーネントは、小道具を介してビデオのデータを渡します。また、このセットを複数のビデオで使用し、1つまたは複数のビデオで正常に動作します。

_<div v-for="video in videos" :key="video.id">
  <video-player :videoName="video.videoName" :videoURL="video.videoURL" :thumbnail="video.thumbnail"></video-player>
</div>
_

Vuexストアのすべてのユーザーに対して、初期状態を汎用ビデオに設定しています。

_getFreeVideo: [
  {
    videoName: "the_video_name",
    videoURL:  "https://demo-video-url.mp4",
    thumbnail: "https://s3.amazonaws.com/../demo-video-poster.jpg"
  }
]
_

これはvideosのデータに設定されます(および後でgetFreeVideoに設定)

_ data () {
   return {
     videos: []
   }
 }
_

Created()ライフサイクル内のストアで、data()のvideosをgetFreeVideoに設定しています。

_    this.videos = this.getFreeVideo
_

..そして、ユーザーが個人的なビデオを持っているかどうかを確認し、created()ライフサイクルで状態を更新します。

_ this.$store.dispatch('getFreeVideo', 'the_video_name')
_

これにより、axiosでリクエストが行われ、ビデオデータが正常に返されます。

MapState _import { mapState } from 'vuex_を使用して、状態の変化を監視しています。

_ computed: {
  ...mapState(['getFreeVideo'])
}
_

_this.videos_が更新されない理由がわかりません。ここで、予想される動作に関する私の仮定は、状態の変更とコンポーネントの再レンダリングから更新される_videos[]_です。

以下に示すように、状態が更新されており、計算されたプロパティ内のvideoUpdate()にも新しいデータがあります。

vuexVuex ..しかし、_videos[]_は更新されないため、ビデオコンポーネントは小道具や新しい小道具などを取得できません。

いくつかのメモ:

  • _v-if_で子コンポーネントを非表示にしようとしています(および状態変更後に表示)
  • setTimeoutを試してみましたが、データは通過し、videoJSプレーヤーは正しくインスタンス化されません(初期データが必要です)
  • ローカルメソッドでこれを試してみました/ Vuex状態を使用していません
  • コンソールにエラー_TypeError: Cannot read property '_withTask' of undefined_が表示されますが、これはデモビデオが正しく読み込まれた場合でも発生するため、これは無関係と思われ、未定義として表示されるものはここにありません。

TL; DR

基本的に、状態の変更後に子コンポーネントを再レンダリングすることはできません。そして、異なる構造で_videos[]_にデータを取得できますが、それでも再レンダリングされません。

データが処理されず、再レンダリングが行われないのはなぜですか?

「反応性を理解する」または説明のないものへのリンクのみを含む回答を投稿しないでください。 ????

@ acdcjuniorに追加

_//action   
getFreeVideo: (context, videoName) => {
    axios({
      method: 'post',
      url: 'https://hidden-for-posting',
      data: {
        action: 'getVideo',
        userId: '1777', // (hardcoded to test)
        videoName: videoName
      },
      headers: {
        'x-api-key': apiKey,
        'Content-Type': 'application/json'
      }
    })
    .then(response => {
      let video = [
        {
          videoName: response.data.videoName,
          videoURL: response.data.videoURLs.mp4,
          thumbnail: response.data.thumbnails['1280']
        }
      ]
      return context.commit('updateGetFreeVideo', video)
    })
    .catch(error => {
      if (error.response) {
        console.log(error.response)
      } else if (error.request) {
        console.log(error.request)
      } else {
        console.log('Error', error.message)
      }
      console.log(error.config)
    })
}

// mutation:
updateGetFreeVideo: (state, payload) => {
  return state.getFreeVideo = payload
}

// getter:
getFreeVideo: state => {
  return state.getFreeVideo
}
_
8
Jordan

テンプレートを考慮して、投稿したコードに基づいて

<div v-for="video in videos" :key="video.id">

以下からvideosを選択します。

 data () {
   return {
     videos: freeVideo
   }
 }

freeVideoから初期化されますが、コードのどこにもvideosの更新と表示されません。

解決策:

計算されたgetFreeVideoにすでに状態がマップされています:

computed: {
  ...mapState(['getFreeVideo'])
}

これを使って:

<div v-for="video in getFreeVideo" :key="video.id">

更新:

Created()ライフサイクル内のストアで、data()のvideosをgetFreeVideoに設定しています。

    this.videos = this.getFreeVideo

これは、this.videosが何であれthis.getFreeVideoを更新し続けるには不十分です。何かがthis.getFreeVideoに設定されるたびに、this.getFreeVideoではなくthis.videosのみが変更されます。

this.videosが変更されるたびにthis.getFreeVideoを自動的に更新する場合は、ウォッチャーを作成します。

watch: {
  getFreeVideo() {
    this.videos = this.getFreeVideo
  }
}

v-forvideosを使用し続けます:

<div v-for="video in videos" :key="video.id">
8
acdcjunior

したがって、問題はすべてvideo.jsにあったことがわかりました。私はこの質問を削除したいと思いますが、助けてくれた人にポイントを失いたくありません。

ここでの解決策と入力は、ウォッチャーの使用またはこれをどのように試みたかを再考するのに役立ちました。中央ストアは正常に機能するため、今のところは中央ストアのみを使用しましたが、これは後でリファクタリングする必要があります。

今のところ、video.jsをプレーヤーとして使用するのをやめなければならず、通常のhtml5ビデオプレーヤーは問題なく動作します。

0
Jordan

計算されたプロパティがテンプレートコードのどこかで参照されていない場合(「使用済み」など)vueは、それに対する反応性をスキップします。

まず、ストアと状態のプロパティを構造化する方法を少し混乱させます。

私は...するだろう:

1)ストア状態に「videos」プロパティがある

2)空の配列として初期化する

3)アプリケーションの起動時に、「デフォルト」ビデオをプッシュする突然変異を加えて、「ロード」デフォルトを正しく設定します

4)mapGetterという名前でコンポーネントにvideosを持っている

5)可能なビデオを「更新」するコンポーネントをロードするたびに、アクションをディスパッチし、適切なミューテーションを呼び出してストアの「ビデオ」プロパティを置き換えます

注:コンポーネントに異なる「デフォルト」ビデオを含めることができる場合は、おそらくストアにvideosとして初期化されたfalseプロパティが必要になります。これにより、ストア内のvideosプロパティのゲッターを使用する計算されたプロパティを持つことができ、それがfalseの場合

つまり、最初の場合

// store
state: {
  videos: []
}

getters: {
  videos(state) { return state.videos } 
}

//components

...
computed: {
  videos() {
    this.$store.getters.videos
  }
}

For the second case


// store
state: {
  videos: false
}

getters: { personal_videos(state) { return state.videos } }

//components
data() { return { default: default_videos } },
computed: {
  ...mapGetters([ 'personal_videos' ]),
  videos() {
    if (this.personal_videos) {
      return this.personal_videos
    } else {
      return this.default
    } 
  }

}

個人:より良い名前を付けます-_-そして最初のオプションが最も明確です

0
m3characters