Vuejs синхронный запрос перед рендерингом данных

У меня есть одностраничное приложение, требующее аутентификации. Когда пользователь был аутентифицирован, посетите несколько страниц или нажмите кнопку перезагрузки в браузере, он запросит API, который предоставит их данные аутентификации. то у меня такая ошибка:

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

Эта ошибка вызвана тем, что vue отображает данные аутентификации, пока запрос к API еще не завершен.

Можно ли заставить vue ждать, пока API запроса не завершится, прежде чем vue отобразит данные аутентификации?

просто более понятно, что здесь происходит. Вот код:

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

person antoniputra    schedule 09.06.2016    source источник
comment
Вы должны опубликовать свой код. Не думаю, что нужно идти синхронно   -  person Yerko Palma    schedule 09.06.2016
comment
@YerkoPalma Я использую vue-router и vuex. в настоящее время я помещаю код (для запроса api) в App.vue при готовности ()   -  person antoniputra    schedule 09.06.2016
comment
@YerkoPalma Мой код похож на общий проект одностраничного приложения, пока я не столкнусь с этой проблемой.   -  person antoniputra    schedule 09.06.2016
comment
Вы используете vue-resource или любую другую библиотеку для HTTP-запросов? как вы читаете ответ с обратным вызовом? обещания?   -  person Yerko Palma    schedule 09.06.2016
comment
да, я использую vue-resource для обработки запроса api   -  person antoniputra    schedule 09.06.2016
comment
Просто обнови мой вопрос   -  person antoniputra    schedule 09.06.2016
comment
По теме: stackoverflow.com/questions/37731656/   -  person ceejayoz    schedule 09.06.2016


Ответы (3)


Проблема, как вы сказали, заключается в том, что вы пытаетесь получить доступ к объекту, которого нет, и из-за ошибки Vue не может отобразить его в следующем тике. Решение состоит в том, чтобы использовать простой v-if, чтобы проверить, загружены ли данные, это работает только для реактивных данных.

корневой компонент

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

другой компонент

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

Я использовал v-if="!dataReady" вместо v-else, потому что он будет устаревшим в Vue 2.0.

person Yerko Palma    schedule 09.06.2016
comment
Кроме того, попробуйте использовать другой перехватчик цикла вместо ready, поскольку готовность вызывается, когда DOM визуализирован, и вы хотите, чтобы этот код был перед этим событием. Предпочитайте ловушку created - person Yerko Palma; 09.06.2016
comment
как насчет того, чтобы вызвать authService в main.js. например: auth.getUser(null, (response) => { router.start(App, '#app') }) затем в App.vue просто получайте данные аутентификации, используя: this.authData = auth.user Я просто пробую это и работаю, как ожидалось. но я не уверен, хорошее ли это решение - person antoniputra; 09.06.2016
comment
потому что, если я использую решение, которое вы дали. в каждом компоненте routerComponent будет много v-if = dataReady. - person antoniputra; 09.06.2016

Вы можете использовать data transition hook с включенной опцией waitForData:

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

Кроме того, если вы не хотите использовать эту опцию, вы можете проверить, загружены ли данные, используя свойство $loadingRouteData.

Подробнее здесь: http://router.vuejs.org/en/pipeline/data.html

person Pantelis Peslis    schedule 10.06.2016

Вы можете просто запретить Vue попытаться получить доступ к свойству объекта, например:

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

В некоторых случаях вы даже можете заменить null на Loading... сообщение.

person crabbly    schedule 10.06.2016