[英]Vue.js: using computed property in method returns undefined error
我有一个从 vuex 获取 state 的计算属性。 在 vuex 内部,使用 axios 设置 state 以从我的 api 获取一些数据。 我的问题是,当我尝试在我的方法中使用这个计算属性时,我得到一个未定义的错误。 这是因为我尝试使用在 vuex 存储中设置之前的数据。 那么在我尝试在我的方法中使用它之前,如何确保设置 boardColumnData 呢?
错误:
Error in mounted hook: "TypeError: Cannot read property 'total' of undefined"
TypeError: Cannot read property 'total' of undefined
AppCharts.vue
<template>
<div id="chart_section">
<div id="charts" v-if="boardColumnData">
<DoughnutChart :chart-data="datacollection" :options="chartOptions" class="chart"></DoughnutChart>
<button v-on:click="fillData">Fill Data</button>
</div>
</template>
<script>
import DoughnutChart from './DoughnutChart';
import { mapGetters } from 'vuex';
export default {
components: {
DoughnutChart
},
computed: {
...mapGetters(['boardColumnData']),
},
data() {
return {
datacollection: null,
chartOptions: null
}
},
mounted() {
this.fillData();
},
methods: {
fillData() {
this.datacollection = {
datasets: [{
data: [this.boardColumnData[0].total.$numberDecimal, this.boardColumnData[1].total.$numberDecimal, this.boardColumnData[2].total.$numberDecimal, this.boardColumnData[3].total.$numberDecimal],
backgroundColor: [
'#83dd1a',
'#d5d814',
'#fdab2f',
'#1ad4dd'
],
borderColor: [
'#83dd1a',
'#d5d814',
'#fdab2f',
'#1ad4dd'
],
}]
};
this.chartOptions = {
responsive: true,
maintainAspectRatio: false,
};
}
}
}
</script>
DoughtnutChart.vue
<script>
import { Doughnut, mixins } from 'vue-chartjs';
const { reactiveProp } = mixins;
export default {
extends: Doughnut,
mixins: [reactiveProp],
props: ['chartData', 'options'],
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
Vuex商店:
import axios from 'axios';
const state = {
defaultPosts: [],
boardPosts: [],
boardColumnData: [],
};
const getters = {
boardColumnData: state => state.boardColumnData,
};
const actions = {
getAllBoardPostData: ({commit}) => {
function getBoardColumns() {
return axios.get('http://localhost:5000/api/summary-board/columns');
}
function getBoardPosts() {
return axios.get('http://localhost:5000/api/summary-board/posts');
}
axios.all([getBoardColumns(), getBoardPosts()])
.then(axios.spread((columnData, postData) => {
let rawPosts = postData.data;
let columns = columnData.data;
let posts = Array.from({length: columns.length}, () => []);
rawPosts.forEach((post) => {
// If column index matches post column index value
if(posts[post.column_index]){
posts[post.column_index].push(post);
}
});
columns.forEach((column, index) => {
let columnTotal = 0;
posts[index].forEach((post) => {
columnTotal += post.annual_value;
});
column.total.$numberDecimal = columnTotal;
});
commit('setBoardColumns', columns);
commit('setBoardPosts', posts);
commit('setDefaultPosts', posts);
}))
.catch(error => console.log(error));
}
};
const mutations = {
setDefaultPosts: (state, payload) => {
state.defaultPosts = payload;
},
setBoardPosts: (state, payload) => {
state.boardPosts = payload;
},
setBoardColumns: (state, payload) => {
state.boardColumnData = payload;
}
};
export default {
state,
getters,
actions,
mutations
};
boardColumnData 看起来像这样:
[
{
"name": "Opportunities",
"percentage": {
"$numberDecimal": "0"
},
"total": {
"$numberDecimal": 70269
}
},
{
"name": "Prospects",
"percentage": {
"$numberDecimal": "0.25"
},
"total": {
"$numberDecimal": 0
}
},
{
"name": "Proposals",
"percentage": {
"$numberDecimal": "0.5"
},
"total": {
"$numberDecimal": 5376
}
},
{
"name": "Presentations",
"percentage": {
"$numberDecimal": "0.75"
},
"total": {
"$numberDecimal": 21480
}
},
{
"name": "Won",
"percentage": {
"$numberDecimal": "1"
},
"total": {
"$numberDecimal": 0
}
},
{
"name": "Lost",
"percentage": {
"$numberDecimal": "1"
},
"total": {
"$numberDecimal": 0
}
},
{
"name": "No Opportunity",
"percentage": {
"$numberDecimal": "1"
},
"total": {
"$numberDecimal": 0
}
}
]
一旦数据到达存储区,Vue 应该能够处理更新组件的反应性,并且由于您将其正确传递到组件中,我认为您只需要进行一些小调整以使组件更具反应性。 我会将datacollection
移动到计算属性,因为它仅依赖于商店的boardColumnData
,然后您能否将您的chartOptions
移动到最初定义,因为它只是 static 数据?
export default {
data: () => ({
// datacollection: null, // remove this
chartOptions: {
responsive: true,
maintainAspectRatio: false,
},
},
//...
computed: {
...mapGetters([
'boardColumnData'
]),
datacollection() { // Property added to computed properties
if (this.boardColumnData.length) { // - check for boardColumnData before using it
return {
datasets: [{
data: [this.boardColumnData[0].total.$numberDecimal, this.boardColumnData[1].total.$numberDecimal, this.boardColumnData[2].total.$numberDecimal, this.boardColumnData[3].total.$numberDecimal],
backgroundColor: [
'#83dd1a',
'#d5d814',
'#fdab2f',
'#1ad4dd'
],
borderColor: [
'#83dd1a',
'#d5d814',
'#fdab2f',
'#1ad4dd'
],
}]
};
} else {
return null;
}
}, // end dataCollection()
},
//... rest of component...
然后在您的模板中,只需检查datacollection
是否具有值。 例如:
<template>
<div id="chart_section">
<div id="charts" v-if="datacollection">
<DoughnutChart
:chart-data="datacollection"
:options="chartOptions"
class="chart"
/>
</div>
</div>
</template>
您可以在调用 fillData 方法之前设置数据,方法是在挂载的钩子上使用 async await。
在 AppCharts.vue 中,在您的 mounted() 挂钩调用 getAllBoardPostData()
`async mounted() {
await this.$store.dispatch('getAllBoardPostData')
this.fillData();
},`
这将从您的 api 获取数据并在加载组件时填充您的存储,并且在调用 fillData() 方法之前
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.