A
A
alphamikle2018-07-23 20:56:15
API
alphamikle, 2018-07-23 20:56:15

How to solve the problem with initialization of the initial state of the Vue.js application?

Good afternoon! Help, knowledgeable people, to understand the following problem:
I am developing a pet on the Vue.js front and Symfony 4 back. Before initializing the application, it is necessary to make a request to the server in order to get routes for api and some other "primary" data - whether the user is authorized, if yes - information about him. The problem is that the request is asynchronous and the data arrives in the application a little later than the application is rendered. I make a request to get api routes in the hook (I tried it in created, beforeCreated, mounted) App.vue, I tried to make it in the main js file, in which the Vue instance is actually created, and create new Vue in the successful callback of this primary request, but there got out a problem with writing the primary data received via api to $store.
Detailed description with files:
The file where modules, router, stores are connected, a Vue instance is created.

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


The main file of the application, in its hooks I tried to load data into the 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>


The same file that already needs a loaded list of routes from $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>

This is what the loaded list of routes looks like:
5b56148774b8c506857026.png
And one more feature, which, in fact, drives into a complete stupor:
5b56152264343544942914.png5b561527afcc1584029799.png

If you display in the ItemsList.vue component the api object itself, located in $store.state, and, in theory, already filled with data, then it will be
this answer:
5b561585d091e485991714.png
but if you display $store.state itself, then the api object in it will be filled with data as it should:
5b5615a94cb2f019282660.png

The question, rather, is not only for a particular case, it was possible to simply write all the routes at once to the initial state of the state, but getting a list of routes from the back is much more convenient, as well as accessing them as objects, and I want to know how correctly make asynchronous requests, preload data, and so on. If something in my question is too banal, don't throw your slippers...

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Anton Anton, 2018-07-23
@alphamikle

You can switch components: https://codepen.io/anon/pen/oMWNrm
or mount only after receiving all the data: https://codepen.io/anon/pen/oMWgLR

L
Lev Roskoshin, 2018-07-23
@anjilnew

If I were you, I would create a separate download page, describe all the initial data loading when logging in on this page. Displayed, in the meantime, some kind of spinner, when all the data was loaded into the store, I would simply do router.push. I actually do this on projects where I need to use a lot of data that I get from the server. In general, there is still such a problem that you are trying to reactively bind data that is stored in an object that does not yet exist, in which case we encounter the problem of reactive binding in Vue and here either use a crutch in the form of Vue.set or beat the object into variables if it the structure is known to be known, or else determine its default value. I hope I described all the pitfalls that you will encounter in this direction

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question