@n2kkrd

Как правильно подгрузить данные через Vuex?

Всем привет!
У меня уже есть готовая реализация вывода данных о студентах их оценках в виде таблицы. Оно реализованно в компоненте GrdGrid.vue и отображается в Grades.vue:
GrdGrid:
<template>
    <v-data-table
        :headers="headers"
        :items="actualGrades"
        :items-per-page="15"
        item-key="code"
        class="elevation-3"
    >

        <template v-slot:top>
            <v-toolbar dense>
                <v-toolbar-title>Таблица грейдов</v-toolbar-title>
                <v-spacer></v-spacer>
                <v-btn class="primary text-lg-button"
                       @click="$store.state.grade.newGradeDialog = true"
                       x-small
                       fab
                >
                +</v-btn>
            </v-toolbar>
        </template>

        <template v-slot:item.grade="editGrade">
            <v-edit-dialog
                :return-value.sync="editGrade.item.grade"
                @save="save(editGrade)"
                @open="open(editGrade.item.grade)"
            >
                {{ editGrade.item.grade }}

                <template v-slot:input>
                    <v-text-field
                        v-model="editGrade.item.grade"
                        :rules="[rules.grade]"
                        label="Грейд"
                    ></v-text-field>
                </template>
            </v-edit-dialog>
        </template>

        <template v-slot:item.actions="item">
            <v-icon @click="deleteItem(item.item)">mdi-delete</v-icon>
        </template>

        <template v-slot:no-data v-if="!$store.state.isLoading">
            <v-btn small color="primary" @click="initData">
                Восстановить данные
            </v-btn>
        </template>
    </v-data-table>
</template>

<script>
export default {
    name: "GrdGrid",

    data() {
        return {
            headers: [
                {text: "Код", value: "code"},
                {text: "Курс", value: "courseName"},
                {text: "ФИО", value: "studentName"},
                {text: "Грейд", value: "grade"},
                {text: "Дата", value: "formatGradeDate", align: "center"},
                {text: "Удалить", value: "actions", align: "center", sortable: false}
            ],

            rules: {
                grade: val => (val && !isNaN(val) && val >= 0 && val <= 25) || "число от 0 до 25"
            },

            currentGradeValue: null
        };
    },

    methods: {
        open(value) {
            this.currentGradeValue = value;
        },
        async save(edit) {
            let isError = 1;
            if (this.rules.grade(edit.item.grade) === true) {
                try {
                    edit.item.grade = Number(edit.item.grade);
                    isError = (await this.$store.dispatch("grade/putGrade", edit.item)).resultCode;

                } catch (error) {
                    console.error(error);
                }
            }
            
            setTimeout(() => (edit.item.grade = isError ? this.currentGradeValue : Number(edit.item.grade)));
        },

        deleteItem(grade) {
            this.$store.dispatch("grade/deleteGrade", grade);
        },

        initData() {
            this.$store.dispatch("grade/initData");
        },
    },

    computed: {
        actualGrades() {
            return this.$store.state.grade.grades.filter(grade => !grade.isDelete);
        }
    },

    async mounted() {
        await this.$store.dispatch("grade/getCourses");
        await this.$store.dispatch("student/getStudents");
        await this.$store.dispatch("grade/getGrades");
    }
};
</script>

Теперь мне нужно создать вторую страницу, которая будет отображать те же самые данные но уже в виде столбчатой и круговой диаграммы. Для этого я создал отображение SecondView.vue и сам компонент который будет в него импортироваться StudentChart.vue, для создание диаграмм я использую библотеку Chart.js. Вот код моего компонента StudentChart:
<template>
  <v-container>
    <v-row>
      <v-col cols="6">
        <v-card>
          <v-card-title>Круговая диаграмма распределения оценок</v-card-title>
          <v-card-text>
            <canvas ref="pieChart" width="400" height="400"></canvas>
          </v-card-text>
        </v-card>
      </v-col>
      <v-col cols="6">
        <v-card>
          <v-card-title>Столбчатая диаграмма распределения оценок по курсам</v-card-title>
          <v-card-text>
            <canvas ref="barChart" width="400" height="400"></canvas>
          </v-card-text>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
import Chart from 'chart.js';

export default {
  name: 'StudentChart',
  data() {
    return {
      pieData: [],
      barData: [],
      pieChart: null,
      barChart: null,
    };
  },
  async created() {
    await this.loadData();
  },
  methods: {
    async loadData() {
      this.pieData = await this.$store.dispatch('grade/getGrades');
      this.barData = await this.$store.dispatch('grade/getCourses');
      this.createPieChart();
      this.createBarChart();
    },
    createPieChart() {
      const data = {
        labels: this.pieData.map((grade) => grade.studentName),
        datasets: [
          {
            data: this.pieData.map((grade) => grade.grade),
            backgroundColor: [
              '#FF6384',
              '#36A2EB',
              '#FFCE56',
              '#8DFF00',
              '#FF5733',
              '#C41E3D',
            ],
            hoverBackgroundColor: [
              '#FF6384',
              '#36A2EB',
              '#FFCE56',
              '#8DFF00',
              '#FF5733',
              '#C41E3D',
            ],
          },
        ],
      };
      const options = {
        responsive: true,
        maintainAspectRatio: false,
        legend: {
          display: true,
          position: 'right',
          align: 'center',
          labels: {
            boxWidth: 20,
            fontSize: 12,
          },
        },
        tooltips: {
          mode: 'index',
          intersect: false,
        },
      };
      this.pieChart = new Chart(this.$refs.pieChart, {
        type: 'pie',
        data,
        options,
      });
    },
    createBarChart() {
      const data = {
        labels: this.barData.map((course) => course.courseName),
        datasets: [
          {
            label: 'Оценки',
            backgroundColor: '#4CAF50',
            data: this.barData.map((course) => course.averageGrade),
          },
        ],
      };
      const options = {
        responsive: true,
        maintainAspectRatio: false,
        scales: {
          yAxes: [
            {
              ticks: {
                beginAtZero: true,
              },
            },
          ],
        },
        legend: {
          display: false,
        },
        tooltips: {
          mode: 'index',
          intersect: false,
        },
      };
      this.barChart = new Chart(this.$refs.barChart, {
        type: 'bar',
        data,
        options,
      });
    },
  },
};
</script>

По итогу в первом случае все данные подгружаются и отображаются в виде таблицы, а во втором случае данные даже не подгружаются. В чем может быть проблема?

Как доп информация - файл grade.js из store:
import api from '@/store/api'

import Grade from '../../model/Grade'
import Course from '../../model/Course'

export default {
    namespaced: true,

    state: {
        courses: new Map(),
        grades: [],
        newGradeDialog: false
    },
    
    mutations: {
        setCourses(state, courses) {
            state.courses.clear();
            courses.forEach(course => {
                state.courses.set(
                    course.code, 
                    new Course(
                        course.code,
                        course.name,
                        course.dateStart,
                        course.dateEnd
                    )
                );
            });
        },
        setGrades(state, grades) {
            state.grades = grades.map(grade => {
                return new Grade(
                    grade.code,
                    grade.courseCode,
                    grade.studentCode,
                    grade.grade,
                    grade.gradeDate,
                    grade.isDelete
                );
            });
        },

        postGrade(state, grade) {
            state.grades.push(
                new Grade(
                    grade.code,
                    grade.courseCode,
                    grade.studentCode,
                    grade.grade,
                    grade.gradeDate,
                    grade.isDelete
                )
            );
        },
        deleteGrade(state, grade) {
            const index = state.grades.indexOf(grade);
            
            grade.isDelete = 1;
            state.grades.splice(index, 1, grade);
        }
    },
    
    actions: {
        async getCourses(context) {
            context.commit('setCourses', await api.course());
        },

        async getGrades(context) {
            context.commit('setGrades', await api.grade());
        },

        async postGrade(context, grade) {
            context.commit('postGrade', await api.postGrade(grade));
        },

        async putGrade(context, grade) {
            return await api.putGrade(grade.code, grade);
        },

        async deleteGrade(context, grade) {
            if(!(await api.deleteGrade(grade.code)).resultCode) {
                context.commit('deleteGrade', grade);
            }
        },

        async initData(context) {
            context.commit('setGrades', await api.initData());
        }
    }
}
  • Вопрос задан
  • 89 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Hexioniq
Не скажу, что такой вариант окажется 100% рабочим, но
думаю часть проблемы заключается в этих строках:
this.pieData = await this.$store.dispatch('grade/getGrades');
this.barData = await this.$store.dispatch('grade/getCourses');
store.dispatch вызывает действие, но не возвращает значение. Допустим, в экшене
async getCourses(context) {
context.commit('setCourses', await api.course());
},
вызывается api.course(), который возвращает значение, условно список курсов или курс, как я понимаю.
Затем, значение коммитится в мутацию setCourses.
В мутации setCourses сначала очищается переменная состояния courses, затем создаётся структура Map, содержащая элементы структуры, состоящие из ключа и значения см. setCourses. Так что, думаю, для доступа к переменным состояния, в данном случае courses, следует определить геттеры( getters ).
Условно:
getCourses( state ) {
return state.courses;
}

А в компоненте SecondView.vue использовать такой вариант:
this.barData = await this.$store.getters.getCourses;
Аналогично стоит поступить и с Grades.
Конечно детали реализации будут зависеть от версии Vue.js и vuex.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы