A
A
Alexey2020-11-12 10:24:34
Vue.js
Alexey, 2020-11-12 10:24:34

How in a Vue application to first load data into $store, and only then render templates?

I have an application with single file components. Vue, Vuex, axios... I
use Vue CLI, Webpack.
My application has a Vuex store $store. Data from $store is used in component templates. $store is populated with data in the main App. Brief structure:

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
...

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')


app.vue
<template>
  <div id="app">
    <v-app>
      <MainContent/>
    </v-app>
  </div>
</template>

<script>
import MainContent from '@/components/MainContent'
import axios from 'axios'
import store from '@/store'

export default {
  name: 'App',
  components: {
    MainContent,
  },
  data: () => {
    return {
      ...
    }
  },
  mounted () {
    const vm = this
    async function loader () {
      const response = await axios.post('https://site.ru/get_data')
      if (response.status === 200) {
        await store.dispatch('setData', response.data.Data)
      }
    }
    loader()
  }
}
</script>

The / route loads a component in MainContent that requires data to be loaded in the mounted.
The problem is that the rendering of this component starts when the data has not yet been loaded. async and await have no effect!
Those. if the user presses F5 on any page of the site that contains a $store dependent component, they will get an error.
How to load data into storage before rendering templates? Of course, you can put v-if in templates with the condition of data availability. But in the component file, there is not only a template, but also code that may contain lifecycle hooks, and they may need data from the $store. Actually, it is. You can put promises there too, but this is somehow very unfeng shui.
Is there a nice solution?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
I
Igor, 2020-11-12
@alenov

const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // вызывается до подтверждения пути, соответствующего этому компоненту.
    // НЕ ИМЕЕТ доступа к контексту экземпляра компонента `this`,
    // так как к моменту вызова экземпляр ещё не создан!
  },
  beforeRouteUpdate (to, from, next) {
    // вызывается когда маршрут, что рендерит этот компонент изменился,
    // но этот компонент будет повторно использован в новом маршруте.
    // Например, для маршрута с динамическими параметрами `/foo/:id`, когда мы
    // перемещаемся между `/foo/1` и `/foo/2`, экземпляр того же компонента `Foo`
    // будет использован повторно, и этот хук будет вызван когда это случится.
    // Также имеется доступ в `this` к экземпляру компонента.
  },
  beforeRouteLeave (to, from, next) {
    // вызывается перед переходом от пути, соответствующего текущему компоненту;
    // имеет доступ к контексту экземпляра компонента `this`.
  }
}

beforeRouteEnter (to, from, next) {
  next(vm => {
    // экземпляр компонента доступен как `vm`
  })
}

Source

A
Alex, 2020-11-12
@Kozack Vue.js

Alexey ,

Well so for this and the whole bazaar)))
I want that no matter which page the user opened, the data for the template would be loaded first, and then the rendering for which this data is needed was already performed. And let him see an awesome loading indicator at this moment))
After all, the user can, for example, save a link to some internal page of the site that needs storage. And then just open it. As I said, there is a solution: conditional rendering of the template through v-if, promises in hooks, etc., etc. And this is in every such component. I want to do it in one place and forget about the need to check in

First: Absolutely every component should check whether some subset of data is loaded without which it cannot work. And each component must decide for itself how to work until this subset is loaded. What to show what to hide.
For example, the header component may not wait until the feed is loaded. And without waiting for the user information to load, display the site menu. Or some form may fully render without waiting for user information, but block submission until that information is loaded.
If not a single component can work for you until absolutely all the data is loaded, this is a shitty architecture.
Secondly, if you're so itchy to do everything in one place - conditional rendering in the App in which the request is made.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question