简体   繁体   English

Vue.js:在方法中使用计算属性返回未定义错误

[英]Vue.js: using computed property in method returns undefined error

I have a computed property that gets the state from vuex.我有一个从 vuex 获取 state 的计算属性。 Inside vuex the state is set using axios to get some data from my api.在 vuex 内部,使用 axios 设置 state 以从我的 api 获取一些数据。 My issue is that when I try use this computed property inside my methods I get an undefined error.我的问题是,当我尝试在我的方法中使用这个计算属性时,我得到一个未定义的错误。 This is because I try use the data before it has been set in the vuex store.这是因为我尝试使用在 vuex 存储中设置之前的数据。 So how do I make sure the boardColumnData is set before I try using it in my methods?那么在我尝试在我的方法中使用它之前,如何确保设置 boardColumnData 呢?

errors:错误:

Error in mounted hook: "TypeError: Cannot read property 'total' of undefined"
TypeError: Cannot read property 'total' of undefined

AppCharts.vue 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 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 store: 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 looks like this: 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 should be able to handle the reactivity of updating your components once the data arrives in the store, and since you're passing it into your component correctly, I think you just need to make some small adjustments to make the component more reactive.一旦数据到达存储区,Vue 应该能够处理更新组件的反应性,并且由于您将其正确传递到组件中,我认为您只需要进行一些小调整以使组件更具反应性。 I'd move the datacollection to a computed property, since it's only dependent on the store's boardColumnData , and then could you move your chartOptions to be defined initially, since it's just static data?我会将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...

and then in your template, just check for if datacollection is has a value.然后在您的模板中,只需检查datacollection是否具有值。 For instance:例如:

<template>
    <div id="chart_section">
        <div id="charts" v-if="datacollection">
            <DoughnutChart
              :chart-data="datacollection"
              :options="chartOptions"
              class="chart"
            />
        </div>
    </div>
</template>

You can set the data before the fillData method is called by using async await on the mounted hook.您可以在调用 fillData 方法之前设置数据,方法是在挂载的钩子上使用 async await。

In AppCharts.vue, inside your mounted() hook call getAllBoardPostData()在 AppCharts.vue 中,在您的 mounted() 挂钩调用 getAllBoardPostData()

`async mounted() {
    await this.$store.dispatch('getAllBoardPostData')
    this.fillData();
},`

This will fetch the data from your api and populate your store when the component is loaded, and before the fillData() method is called这将从您的 api 获取数据并在加载组件时填充您的存储,并且在调用 fillData() 方法之前

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Vue.js 这在计算属性中是未定义的 - Vue.js this is undefined inside computed property 使用 Vue.js 中的方法过滤计算属性的数组 - Filter array of a computed property using a method in Vue.js Vue.js 计算属性:[Vue 警告]:渲染错误:“TypeError:无法读取未定义的属性‘userId’” - Vue.js computed property : [Vue warn]: Error in render: "TypeError: Cannot read property 'userId' of undefined" vue.js 不能在计算方法中使用数据属性 - vue.js cannot use data property in computed method 使用 Vue.js 原型返回 undefined - Using Vue.js prototype returns undefined Vue.js (vuex)。 重新加载页面时,计算属性返回未定义。 (vuex 中对象数据的硬编码数组) - Vue.js (vuex). Computed property returns undefined when reloading the page. (Hard coded array of objects data in vuex) Vue.js + Nuxt.js-在单元测试head()方法时,为什么我的计算属性未定义? - Vue.js + Nuxt.js - Why is my computed property undefined when I unit test a head() method? 使用带有Avoriaz的AVA在Vue.js中测试计算属性 - Test computed property in Vue.js using AVA with Avoriaz Vue.js 使用计算属性来显示或隐藏组件的一部分 - Vue.js using a computed property to show or hide part of a component 为什么 vue.js 计算得到未定义 - why vue.js computed get undefined
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM