1
votes

Vue attendant les données des accessoires avant de les utiliser

Je continue à rencontrer un problème où j'attends des données d'un accessoire pour faire quelque chose à l'intérieur de mon hook créé. Il continue de lancer des erreurs telles que "this.value is not defined" (car il n'a pas encore été chargé depuis prop)

J'ai résolu certains de ces problèmes en utilisant v-if et en n'utilisant que si nécessaire. Cependant, dans certains cas, je voulais utiliser ces informations prop dans ma création et lorsque cela se produit, je finis par avoir des erreurs et je ne suis pas sûr de la meilleure façon de dire à cette partie de la création "d'attendre" les données avant de courir.

Aucun conseil?

-

Mettez à jour pour ajouter un exemple de code.

Sur la page App.js, j'appelle le "userInfo" et je le place dans des données comme ça. Je fais cela pour deux raisons. Tout d'abord pour vérifier si l'utilisateur est connecté, et deuxièmement, prendre le temps de sauvegarder les informations de l'utilisateur car elles seront utilisées plus tard dans l'application. (Veuillez noter que user et userInfo sont différents et contiennent des informations différentes. L'utilisateur est un email / mot de passe tandis que userInfo est un nom d'utilisateur, une bio, etc.)

if(this.userInfo) {
  value = true  
}

Maintenant, je transmets ces informations à l'aide de v-bind. puis appelez-le dans les zones où j'ai besoin d'informations en utilisant des accessoires.

Le problème survient lorsque je veux faire quelque chose comme -

data() {
  return {
    user: null,
    userInfo: null,
  }
},
created(){
//let user = firebase.auth().currentUser
  firebase.auth().onAuthStateChanged((user) => {
    if(user){
      this.user = user
      let ref = db.collection('users')
      .where('user_id', '==', this.user.uid)
      ref.get().then(snapshot => {
      snapshot.forEach(doc => {
        this.userInfo = doc.data()
      })
    })

    } else {
      this.user = null
    }
  })
},

L'appel de this.userInfo génère une erreur "this.userInfo is null" (je le mets à null dans les données () de la page par défaut).


7 commentaires

Avez-vous essayé d'utiliser les variables dans mounted au lieu de created ?


Vous pourriez partager un exemple de votre code. Cependant, vous décrivez un état dans lequel l'accessoire passé n'existe même pas encore comme une réponse de promesse. Serait-ce la raison?


@ Aer0 peut-être, bien que je passe des accessoires d'App.vue à une page. Il se charge et est utilisable dans les méthodes, mais n'est pas prêt tout de suite lorsque le document se charge (ou même lorsqu'il est monté, semble-t-il)


@Jesper Je viens de tenter le coup et il semble toujours qu'il l'attrape trop tôt?


@ KJParker Je suppose que vous partagez du code avec nous. Peut-être plus facile de localiser le problème. Cependant, je suppose toujours que c'est un problème de promesse / asynchrone. La promesse peut être résolue lors de l'utilisation dans une méthode mais pas au début (hook créé).


Ouais désolé @ Aer0 a juste pris un peu de formatage car c'était un désordre :) J'ai mis à jour ma question pour contenir des exemples


@KJParker Que diriez-vous de immediate watch immediate ?


3 Réponses :


0
votes

Les accessoires doivent être disponibles dans le crochet created . En supposant que les valeurs sont synchrones. Essayez d'ajouter default valeurs default , afin de supprimer les directives v-if inutiles. Cela devrait résoudre le problème des données synchrones et asynchrones.

{
  props: {
    length: {
      type: Number,
      default: 0,
    },
  },
}


4 commentaires

Et si un accessoire était Promise ? Je pense que c'est le problème ici.


Je viens de modifier ma réponse. Dans ce cas, ils ne sont certainement pas immédiatement disponibles.


Même si cela aide et devrait être la meilleure pratique de définir une valeur par défaut, ce n'est toujours pas la réponse à la question. Si vous comptez sur une valeur à définir correctement pendant le hook created() vous devez vous assurer qu'elle est configurée lors de la création du composant ou utiliser une autre façon de vous fier à votre Pop.


@ Aer0 ce n'est pas juste. Vous pourriez avoir un comportement spécifique au cas où les données ne seraient pas là. Ce que vous dites n'est certainement pas une pratique exemplaire.



5
votes

Comme déjà mentionné dans les commentaires, vous rencontrez un problème de résolution de Promise. Lorsque vous passez un résultat en tant que Prop qui est résolu par une promesse, ce résultat sera fondamentalement vide, ce qui entraînera éventuellement une erreur dans le hook created() vos composants enfants.

Je recommanderais d'utiliser v-if comme vous l'avez déjà fait dans le composant enfant lui-même. Cependant, j'utiliserais le v-if dans le composant parent pour simplement afficher / masquer l'enfant. Cela devrait non seulement résoudre le problème dans votre hook created() , mais également aider à créer un balisage plus lisible dans votre composant enfant où vous pouvez simplement supprimer tous les v-if s.

Supposons donc que vous ayez une relation parent / enfant comme celle-là.

<SomeParentComponent>
  <SomeChildComponent :someProp="yourProp" v-if="yourProp" />
</SomeParentComponent>                           <!-- ^-- See here -->

Lorsque yourProp est défini après une promesse de résolution, la valeur initiale sera null , undefined ou celle que vous avez définie. Pour éviter de passer un accessoire vide, vous pouvez simplement envelopper le dans un v-if dont l'expression s'évalue à yourProp comme cela.

<SomeParentComponent>
  <SomeChildComponent :someProp="yourProp" />
</SomeParentComponent>

Ce faisant, l'enfant ne sera rendu que lorsque yourProp est défini et par conséquent, vous n'obtiendrez plus aucune erreur.


3 commentaires

Ah ok super! Merci @ Aer0 qui fonctionne parfaitement! Quel genre d'impact cela a-t-il sur la vitesse de chargement. Je suppose que cela dépend du temps qu'il faut pour récupérer ces données initiales / mettre à jour l'enfant? Existe-t-il également un meilleur moyen d'éviter cela à l'avenir?


Vous suggérez l'utilisation d'une direction v-if , qui créera un comportement de saut, lorsque les données asynchrones sont disponibles pour les composants ci-dessous.


C'est correct. Si vous transmettez une promesse comme accessoire, vous pouvez attendre que la promesse se résolve de manière async . De plus, avoir un comportement nerveux est quelque chose dont vous devez vous soucier différemment. Si vos données dépendent de votre accessoire pour s'afficher correctement, vous obtiendrez également un comportement instable, même avec une valeur par défaut.



1
votes

Il y a au moins deux approches auxquelles je peux penser:

1. Injection de dépendance

Le parent / racine pour provide les données / objets dans l'arborescence des composants et l'extrémité de réception (enfants) pour les inject .

Parent

import { mapState } from 'vuex';

export default {
  computed: {
    ...mapState([
      'userInfo'
    ])
  },

  created() { },
  mounted() { },
  methods() { 
    if (this.userInfo) {
      // Do something safely
    }
  },
  // Anywhere
}

Enfants

export default {
  created() {
    // On firebase success callback
    this.$store.commit('UPDATE_USER', doc.data());
  }
}

2. Magasin Vuex

Plutôt que de passer des accessoires et d'avoir à gérer d'éventuels problèmes d'asynchronie; vous pouvez laisser Vuex se charger de la synchronisation des états pour vous et cesser de vous inquiéter du fait que les données soient null ou undefined .

Boutique

export default {
  state: {
    userInfo: null
  },
  mutations: {
    UPDATE_USER(state, payload) {
      state.userInfo = payload;
    }
  }
}

Parent / App.js

// Children
{
  inject: ['userInfo'],

  created() {
    if (this.userInfo) {
      // Do something 
    }
  },
  mounted() {
    if (this.userInfo) {
      // Do something 
    }
  },
  // Any lifecycle hooks, methods or virtually anywhere needing a reference to this object
}

Enfants

{
  data: () => ({
    userInfo: null
  }),

  created() {
    // Populates data via Firebase 
    // Code omitted for brevity...

    this.userInfo = doc.data();
  },

  provide() {
    return Object.defineProperty({}, 'userInfo', {
      get: () => this.userInfo
    })
  }
}


0 commentaires