@alphamikle

Как решить проблему с инициализацией начального состояния приложения Vue.js?

Добрый день! Помогите, знающие люди, разобраться в следующей проблеме:
Разрабатываю домашнего питомца на Vue.js фронте и Symfony 4 бэк. Перед инициализацией приложения необходимо выполнить запрос к серверу, чтобы получить роуты для api и некоторые другие "первичные" данные - авторизован ли пользователь, если да - информация о нем. Проблема в том, что запрос асинхронный и данные прилетают в приложение немного позже, чем приложение отрендерится. Запрос на получение роутов api произвожу в хуке (пробовал в created, beforeCreated, mounted) App.vue, пробовал сделать его в главном файле js, в котором, собственно, создается экземпляр Vue, и в успешном колбеке этого первичного запроса создавать new Vue, но там вылезла проблема с записью полученных по api первичных данных в $store.

Детальное описание с файлами:
Файл, где подключаются модули, роутер, стора, создается экземпляр Vue.
app.js
import Vue from 'vue';
import axios from 'axios';
import vueAxios from 'vue-axios';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './vue/App';

import LoginForm from './vue/element/LoginForm';
import ItemsList from './vue/element/ItemsList';
require('../css/app.styl');

Vue.component('App', App);
Vue.use(VueRouter);
Vue.use(vueAxios, axios);
Vue.use(Vuex);

Vue.use(ElementUI);
Vue.use(LoginForm);

const router = new VueRouter({
    mode: 'history',
    routes: [
        {path: '/', component: LoginForm, name: 'LoginForm'},
        {path: '/list/', component: ItemsList, name: 'ItemsList'},
    ],
});

const store = new Vuex.Store({
    state: {
        isAuth: false,
        user: {},
        itemsList: {},
        filterOptions: {},
        path: router.currentRoute.path,
        api: {},
        pagination: {},
    },
    mutations: {
        set(state, {type, value}) {
            state[type] = value;
        },
        go(state, {path}) {
            router.push(path);
            state.path = path;
        },
        multiSet(state, {value}) {
            for (let key in value) {
                state[key] = value[key];
            }
        }
    },
    getters: {
        getPath: state => {
            state.path = router.currentRoute.path;
            return state.path;
        },
    },
});

const vm = new Vue({
    el: '#app',
    router,
    store
});



Главный файл приложения, в его хуках я пытался загрузить данные в стору
App.vue
<template>
    <div class="app">
        <header-navigator :defaultIndexProp="defaultIndexProp"></header-navigator>
        <transition name="el-fade-in" mode="out-in">
            <router-view @goToList="toList" v-if="api"></router-view>
        </transition>
    </div>
</template>

<script>
    import HeaderNavigator from './element/HeaderNavigator';
    import LoginForm from "./element/LoginForm";
    export default {
        name: 'app',
        components: {
            LoginForm,
            HeaderNavigator
        },
        computed: {
            api() {
                return this.$store.state.api;
            }
        },
        data() {
            return {
                defaultIndex: window.location.path,
                defaultIndexProp: window.location.path,
            }
        },
        methods: {
            toList() {
                this.defaultIndexProp = '/list/';
            }
        },
        mounted() {
            this.axios.get('/api/init/').then(r => {
                const {data} = r;
                this.$store.commit('multiSet', {value: data});
            });
        }
    }
</script>

<style>
</style>



Тот самый файл, в котором уже нужен загруженный список роутов из $store.state.api
ItemsList.vue
<template>
    <el-card></el-card>
</template>

<script>
    export default {
        name: 'ItemsList',
        data() {
            return {

            }
        },
        computed: {
            api() {
                return this.$store.state.api;
            }
        },
        created() {
            this.axios({
                url: this.api.items.path,
                method: this.api.items.method
            }).then(r => {
                const {data} = r;
                this.$store.commit('multiSet', {value: data});
            }).catch(e => {

            });
        }
    }
</script>

<style lang="stylus">
</style>

Вот так выглядит загруженный список роутов:
5b56148774b8c506857026.png
И еще одна особенность, которая, собственно, вгоняет в полный ступор:
5b56152264343544942914.png5b561527afcc1584029799.png


Если вывести в компоненте ItemsList.vue сам объект api, находящийся в $store.state, и, по идее, уже заполненный данными, то будет
такой ответ:
5b561585d091e485991714.png
но если вывести сам $store.state, то в нем объект api будет заполнен данными как и надо:
5b5615a94cb2f019282660.png


Вопрос, скорее, не только к частному случаю, можно было и просто записать сразу все роуты в начальное состояние state'a, но получать список роутов с бека намного удобнее, как и обращаться к ним, как к объектам, да и узнать хочу, как правильно делать асинхронные запросы, предзагружать данные и тд. Если что-то в моем вопросе слишком банальное, не кидайте тапки...
  • Вопрос задан
  • 2708 просмотров
Решения вопроса 1
Fragster
@Fragster
помогло? отметь решением!
Можно переключать компоненты: https://codepen.io/anon/pen/oMWNrm
или монтировать только после получения всех данных: https://codepen.io/anon/pen/oMWgLR
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@anjilnew
frontend
Я бы на вашем месте создал отдельную страницу загрузки, описал бы всю первичную загрузку данных при логине на этой странице бы. Отображал, тем временем какой нибудь спинер, когда все данные загрузил в стор просто сделал бы router.push. Я собственно так и поступаю на проектах где мне нужно использовать много данных которые я получаю с сервера. А вообще еще встречается такая проблема, что вы пытаетесь связать реактивно данные которые храняться в объекте которого еще нет , в таком случае мы встречаемся с проблемой реактивной связки в Vue и тут либо использовать костыль в виде Vue.set или же бить объект на переменные если его структура заведомо известно , или же определять ему дефотное значение. Надеюсь описал все подводные камни с которыми столкнетесь в этом направлении
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы