web-dev-qa-db-fra.com

Vuejs demande de manière synchrone avant le rendu des données

J'ai une application d'une seule page qui nécessite une authentification. Lorsque l'utilisateur a été authentifié, visitez certaines pages ou appuyez sur le bouton de rechargement dans le navigateur, il demandera une API qui fournira leurs données d'authentification. alors j'ai une erreur comme celle-ci:

[Vue warn]: Error when evaluating expression "auth.name": TypeError: Cannot read property 'name' of null (found in component: <navbar>)

Cette erreur est due au fait que vue render données d'authentification alors que la demande à l'API n'est pas encore terminée.

Est-il possible de faire vue attendre l'api de la requête jusqu'à la fin en premier, avant vue render données d'authentification?

juste plus clairement ce qui se passe ici. Voici le code:

// main.js
import Vue from 'vue'
import App from './App.vue' // root vue
import store from './vuex/store' // vuex
import router from './router' // my router map

sync(store, router)
router.start(App, '#app')
// end main.js



// App.vue
<template>
  <main>
    <div class="wrapper">
      <router-view></router-view>
    </div>
  </main>
</template>

<script>
  import authService from './services/auth' // import authservice

  ready () {
    // here is code that should be done first before vue render all authData
    auth.getUser((response) => {
      self.authData = response
    })
  },
  data () {
    return {
      authData: null // default is null until the api finish the process
    }
  }
</script>
// end App.vue



// SomeRouterComponents.vue
<template>
  <!-- some content -->
  <div>
    // always got error: cannot read property 'name' of null
    // here I expect to render this after api has been resolved
    {{ $root.authData.name }}
  </div>
  <!-- some content -->
</template>
12
antoniputra

Le problème, comme vous l'avez dit, est que vous essayez d'accéder à un objet qui n'est pas présent, et à cause de l'erreur, Vue ne peut pas le restituer dans le prochain tick. La solution est d'utiliser un simple v-if pour vérifier si les données sont chargées, cela ne fonctionne que pour les données réactives.

composant racine

  import auth from './services/auth' // import authservice

  ready () {
    // here is code that should be done first before vue render all authData
    auth.getUser((response) => {
      self.authData = response
      self.dataReady = true
    })
  },
  data () {
    return {
      authData: null, // default is null until the api finish the process
      dataReady: false
    }
  }

autreComposant

  <div v-if="dataReady">
    // note that if you use v-show you will get the same error
    {{ $root.authData.name }}
  </div>
  <div v-if="!dataReady">
    // or some other loading effect
    Loading...
  </div>

J'ai utilisé v-if="!dataReady" au lieu de v-else car il sera obsolète dans Vue 2.0

13
Yerko Palma

Vous pouvez simplement empêcher Vue d'essayer d'accéder à la propriété de l'objet, comme ceci:

{{ $root.authData ? $root.authData.name : null }}

Vous pouvez même changer null pour un Loading... message dans certains cas.

2
crabbly

Vous pouvez utiliser le data transition hook avec l'option waitForData activée:

<script>
  import authService from './services/auth'

  export default {
    route: {
      waitForData: true, // wait until data is loaded

      data (transition) {
        authService.getUser((response) => {
          transition.next({ authData: response }) // set data
        })
      }
    },

    data () {
      return {
        authData: null
      }
    }
  }
</script>

De plus, si vous ne souhaitez pas utiliser cette option, vous pouvez vérifier si les données sont chargées en utilisant le $loadingRouteData propriété.

Plus de détails ici: http://router.vuejs.org/en/pipeline/data.html

2
Pantelis Peslis