【问题标题】:Vuex state not being initialised before router-view component being rendered - undefined error在渲染路由器视图组件之前未初始化 Vuex 状态 - 未定义的错误
【发布时间】:2020-07-07 08:44:43
【问题描述】:

我对 vue 比较陌生,遇到了一个小问题。我正在渲染一个依赖于 vuex 中存储的状态的组件。我从应用程序主要部分的 json 文件中加载此信息。如果我在加载时始终位于应用程序的根目录 (index.html) 上,则一切正常。但是,如果我从路由器动态生成的页面刷新应用程序,我会遇到错误:

[Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"

found in

---> <Room>
       <RoomsOverview>
         <Root>

据我所知,正在发生的事情是该组件正在尝试访问 vuex 中的状态,但尚未初始化。这是组件(Room.vue):

<template>
    <div id="room">
        <h2>{{ roomName }}</h2>
        <div v-for="device in deviceList" v-bind:key="deviceList.name">
            {{ device.name }} - {{ device.function}}
            <svg-gauge v-bind:g-value="device.value" v-bind:g-min="0" v-bind:g-max="50" v-bind:g-decplace="1" g-units="&#8451;">
                <template v-slot:title>
                    Temperature
                </template>
            </svg-gauge>
        </div>
    </div>
</template>

<script>
module.exports = {
    name: 'room',

    /** Load external component files
     *  Make sure there is no leading / in the name
     *  To load from the common folder use like: 'common/component-name.vue' */
    components: {
        'svg-gauge': httpVueLoader('components/DisplayGauge.vue'),
    }, // --- End of components --- //
    
    data() {
        return {

        };
    },
    computed: {
        roomName() {
//            return this.$route.params.roomId;
            return this.$store.getters['rooms/getRoomById'](this.$route.params.roomId);
        },
        deviceList() {
            return this.$store.getters['rooms/getDevicesinRoom'](this.$route.params.roomId);
        },
    },
}
</script>

错误是由行触发的

            return this.$store.getters['rooms/getRoomById'](this.$route.params.roomId);

这会尝试访问 getter 中的当前状态:

    getRoomById: (state) => (id) => {
        return state.rooms.find(room => room.id === id).name; // Needs fixing!
    },

但似乎数组:

// Initial state
const stateInitial = {
    rooms: [],
};

在这些情况下尚未初始化。初始化发生在挂载钩子中 index.js 中应用程序的主入口点

        // Load data from node-red into state
        vueApp.$store.dispatch('rooms/loadRooms')

loadRooms 使用 axios 获取数据的地方。如果我到达站点的根目录 (http://192.168.0.136:1880/uibuilderadvanced/#/),这将按预期工作,但如果我到达诸如 (http://192.168.0.136:1880/uibuilderadvanced/#/rooms/office) 之类的链接,则不会。我怀疑这完全取决于事情发生的顺序,而我的大脑还没有完全考虑清楚。如果有人对如何捕捉它有任何想法,我将不胜感激 - 我认为需要某种观察者,或者 v-if (但我看不到将它放在哪里,因为 Room.vue 是由路由器动态创建的- 见下文)。

谢谢

马丁

更多信息:

房间组件本身是由路由视图从父级(RoomsOverview.vue)中生成的:

<template>
    <div id="rooms">
        <b-alert variant="info" :show="!hasRooms">
            <p>
                There are no rooms available yet. Pass a message that defines a room id and device id 
                to the uibuilder node first. See <router-link :to="{name: 'usage_info'}">the setup information</router-link> 
                for instructions on how start using the interface.
            </p>
        </b-alert>
        
        <router-view></router-view>
    </div>
</template>

<script>
module.exports = {
    name: 'RoomsOverview',
    data() {
        return {

        };
    },
    computed: {
        hasRooms() {
            return this.$store.getters['rooms/nRooms'] > 0;
        },
        roomList() {
            return this.$store.getters['rooms/getAllRooms'];
        },
    },
}
</script>

并且依赖于路由器文件:

const IndexView = httpVueLoader('./views/IndexView.vue');
const AdminView = httpVueLoader('./views/AdminView.vue');

export default {
    routes: [
        {
            path: '/',
            name: 'index',
            components: {
                default: IndexView,
                menu: HeaderMenu,
            },
        },
        {
            path: '/rooms',
            name: 'rooms_overview',
            components: {
                default: httpVueLoader('./components/RoomsOverview.vue'),
                menu: HeaderMenu,
            },
            children: [
                {
                    path: ':roomId',
                    name: 'room',
                    component: httpVueLoader('./components/Room.vue'),
                },
            ],
        },
        {
            path: '/admin',
            name: 'admin', 
            components: {
                default: AdminView,
                menu: HeaderMenu,
            },
            children: [
                {
                    path: 'info',
                    name: 'usage_info',
                    component: httpVueLoader('./components/UsageInformation.vue'),
                }
            ]
        },
    ],
};

【问题讨论】:

    标签: vue.js vuex


    【解决方案1】:

    看来您已经找到问题所在了。 当您登陆主入口点时,将触发 axios 调用,并且您在商店中拥有所需的所有数据。但是,如果您登陆组件本身,则不会触发 axios 调用并且您的商店是空的。

    要解决这个问题,您可以在组件中添加一些条件逻辑,以便在所需数据未定义或为空时执行 axios 调用。

    【讨论】:

    • 谢谢,我在 -
      中添加了逻辑,其中 hasRooms 执行以下检查 - return this.$store.getters['房间/nRooms'] > 0;这似乎在没有进行 axios 调用的情况下修复了它,这似乎很奇怪???
    • 会不会是你的 axios 调用总是被触发,但是当你登陆房间页面时结果还没有准备好?当您获取房间数据时,尝试在 axios 调用上放置一个 console.log('received') 。然后,登陆房间组件并在控制台中检查是否已发出请求
    • 嗯,所以无论我登陆哪个页面都会触发它(我在变异函数中放置了一个 console.log),因此结果肯定还没有准备好。 v-if 逻辑似乎确实消除了错误 - 再次感谢!
    猜你喜欢
    相关资源
    最近更新 更多
    热门标签