web-dev-qa-db-fra.com

Vue.js: les données ne sont pas mises à jour avec le changement d'état, donc le rendu ne se produit jamais

J'ai un composant réutilisable qui est un lecteur vidéo video.js. Ce composant fonctionne correctement lorsque les données sont transmises lors du chargement initial du DOM.

Je dois comprendre pourquoi mon composant n'est pas re-rendu après la mise à jour de l'état dans Vuex.

Le composant Parent transmet les données de la vidéo via des accessoires. J'ai également cet ensemble pour être utilisé avec plusieurs vidéos et cela fonctionne bien avec un seul ou plusieurs.

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

Je règle l'état initial sur une vidéo générique pour tous les utilisateurs de mon magasin Vuex.

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

Ceci est défini dans les données dans videos(et plus tard à getFreeVideo)}

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

Je mets videos dans data () pour obtenirFreeVideo dans le magasin au cours du cycle de vie created ():

    this.videos = this.getFreeVideo

..et vérifier si un utilisateur a une vidéo personnelle et mettre à jour l'état dans le cycle de vie created ().

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

Cela fait une demande avec axios et renvoie nos données vidéo avec succès.

J'utilise mapState import { mapState } from 'vuex pour surveiller un changement d'état.

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

Je ne vois pas pourquoi this.videos n'est pas mis à jour. Ici, mon hypothèse concernant le comportement attendu serait que les vidéos [] soient mises à jour à partir du changement d'état et d'un re-rendu du composant.

Comme vous pouvez le voir ci-dessous, l'état a été mis à jour et la méthode videoUpdate () dans les propriétés calculées contient également les nouvelles données:

 vuex  Vuex ..mais les vidéos [] n'étant jamais mises à jour, le composant vidéo ne reçoit jamais les accessoires, les nouveaux accessoires, etc.

Quelques notes:

  • déjà essayé, cachant le composant enfant avec v-if (et montrant après le changement d'état)}
  • essayé setTimeout pour tester des choses, mais les données vont arriver et ensuite le lecteur videoJS n'instancie jamais correctement (doit avoir les données initiales)}
  • essayé de le faire avec une méthode locale/ne pas utiliser l'état Vuex
  • la console affiche l'erreur TypeError: Cannot read property '_withTask' of undefined, mais cela se produit même lorsque la vidéo de démonstration est chargée correctement. Cela ne semble donc pas être lié et je ne trouve rien ici qui se présente comme indéfini.

TL; DR

En gros, je ne parviens pas à rendre le composant enfant après le changement d'état. Et bien que je puisse obtenir les données dans videos[] avec une structure différente, elles ne sont toujours pas restituées.

Pourquoi les données ne parviennent-elles pas à passer au travers, et la restitution n’arrive-t-elle jamais?

_ {Merci de ne pas poster de réponses qui ne contiennent que des liens vers 'comprendre la réactivité' ou quelque chose sans explication.} ????

ajouté pour @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
}
2
Jordan

Sur la base du code que vous avez posté, en considérant le modèle:

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

Il choisit la videos parmi:

 data () {
   return {
     videos: freeVideo
   }
 }

Bien qu'il soit initialisé à partir de freeVideo, nulle part dans votre code, vous affichez une update de videos.

Solution:

Vous avez déjà l'état mappé dans la getFreeVideo calculée:

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

Utilise le:

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

Mettre à jour:

Je mets videos dans data () pour obtenirFreeVideo dans le magasin au sein du fichier cycle de vie created ():

    this.videos = this.getFreeVideo

Ce n'est pas suffisant pour garder this.videos mis à jour avec quoi que ce soit this.getFreeVideo. Chaque fois que quelque chose est défini sur this.getFreeVideo, il ne fera que changer this.getFreeVideo, pas this.videos.

Si vous souhaitez mettre à jour automatiquement this.videos chaque fois que this.getFreeVideo change, créez un observateur:

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

Et continuez à utiliser videos dans le v-for:

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

Si la propriété calculée n'est pas référencée (par exemple, "utilisé"), votre vue de code de modèle ignorera la réactivité correspondante.

Tout d'abord, la structure du magasin et les propriétés de l'état sont un peu confuses. 

Je voudrais:

1) Avoir une propriété "vidéos" dans l'état du magasin

2) Initialisez-le comme un tableau vide

3) Au démarrage de l'application, remplissez-le correctement avec les valeurs par défaut "load", avec une mutation qui lui applique la vidéo "par défaut"

4) Ayez les composants mapGetter sous le nom de videos

5) Chaque fois que vous chargez un composant qui "met à jour" les vidéos possibles, envoyez l'action et appelez la mutation appropriée pour remplacer la propriété "vidéos" du magasin.

Remarque: Si les composants peuvent avoir différentes vidéos "par défaut", vous souhaiterez probablement avoir une propriété videos dans le magasin initialisé avec false. Cela vous permet ensuite d’avoir une propriété calculée qui utilise le getter pour la propriété videos dans le magasin et s’il est false 

Ce que je veux dire, c'est, pour le premier cas

// 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
    } 
  }

}

Personnel: donnez-leur de meilleurs noms -_- et la première option est la plus claire. 

1
m3characters

En fin de compte, tout le problème était avec video.js. Je suis à moitié tenté de supprimer cette question, mais je ne voudrais pas que quiconque aide à perdre des points.

La solution et l'entrée ici ont aidé à repenser mon utilisation des observateurs ou la façon dont j'essayais de le faire. Pour l’instant, j’ai juste utilisé le magasin central car cela fonctionne bien, mais cela devra être refait ultérieurement.

Je devais renoncer à utiliser video.js en tant que lecteur pour le moment, et un lecteur vidéo html5 standard fonctionne sans problème.

0
Jordan