【发布时间】: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="℃">
<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'),
}
]
},
],
};
【问题讨论】: