6

我正在尝试使用 react-chartjs-2 更新我的图表。我正在使用日期选择器来过滤不同的数据并相应地重新渲染图表,例如显示今天、昨天、过去 7 天的数据等。数据正在从我的数据库中获取

但是,当图表被重绘并重新渲染时,它会被添加到我不想要的状态中。我只是想重新渲染请求的新数据而不是重新渲染并添加到图表中的旧数据中。

实际上,我之前使用 vanilla JavaScript 解决了这个问题,因为我没有使用 react 我使用destroy()了图表文档说要使用的方法,但我不确定如何将它与 react 一起使用?

因此,经过进一步检查,我的图表似乎重新渲染得很好。然而,当它被重新渲染时,额外的数据被添加到我不想要的我的 chartData 状态,我只希望被请求的新数据显示在图表上。我仍在试图弄清楚那部分。

这是我的代码,我有很多,所以我只会显示相关部分:

import React from "react";

import reportsService from "../../services/reportsService";
import update from "react-addons-update";
import moment from "moment";

import { Bar } from "react-chartjs-2";
import "chartjs-plugin-labels";
import "chartjs-plugin-datalabels";

class Reportspage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      chartData: {
        labels: [],
        datasets: [
          {
            //label: "Quotes",
            data: [],
            backgroundColor: []
          }
        ]
      }
    };
  }

  chartColors() {
    let colors = [];
    for (let i = 0; i < 100; i++) {
      let r = Math.floor(Math.random() * 200);
      let g = Math.floor(Math.random() * 200);
      let b = Math.floor(Math.random() * 200);
      let c = "rgb(" + r + ", " + g + ", " + b + ")";
      colors.push(c);
    }

    // Update deep nested array of objects in state
    this.setState({
      chartData: update(this.state.chartData, {
        datasets: { 0: { backgroundColor: { $set: colors } } }
      })
    });
  }

  datePicker() {
    let _this = this;
    let start = moment().subtract(29, "days");
    let end = moment();
    let showReports;
    let data;
    let reloNames = [];
    let reloCount = [];

    function focusDate(start, end) {
      $("#daterangePicker span").html(
        start.format("MMMM D, YYYY") + " - " + end.format("MMMM D, YYYY")
      );
    }

    $("#daterangePicker").daterangepicker(
      {
        startDate: start,
        endDate: end,
        ranges: {
          Today: [moment(), moment()],
          Yesterday: [
            moment().subtract(1, "days"),
            moment().subtract(1, "days")
          ],
          "Last 7 Days": [moment().subtract(6, "days"), moment()],
          "Last 30 Days": [moment().subtract(29, "days"), moment()],
          "This Month": [moment().startOf("month"), moment().endOf("month")],
          "Last Month": [
            moment()
              .subtract(1, "month")
              .startOf("month"),
            moment()
              .subtract(1, "month")
              .endOf("month")
          ]
        }
      },
      focusDate
    );

    focusDate(start, end);

    $("#daterangePicker").on("apply.daterangepicker", async function(
      event,
      picker
    ) {
      switch (picker.chosenLabel) {
        case "Today":
          showReports = await reportsService.reloQuotes({
            reportStatus: "Today"
          });

          data = showReports.recordsets[0];

          data.forEach((element, index, array) => {
            reloNames.push(element.reloNames);
            reloCount.push(element.NoofOrders);
          });

          _this.setState({
            chartData: update(_this.state.chartData, {
              labels: { $set: reloNames },
              datasets: { 0: { data: { $set: reloCount } } }
            })
          });

          console.log(_this.state);

          break;
        case "Yesterday":
          showReports = await reportsService.reloQuotes({
            reportStatus: "Yesterday"
          });

          data = showReports.recordsets[0];

          data.forEach((element, index, array) => {
            reloNames.push(element.reloNames);
            reloCount.push(element.NoofOrders);
          });

          _this.setState({
            chartData: update(_this.state.chartData, {
              labels: { $set: reloNames },
              datasets: { 0: { data: { $set: reloCount } } }
            })
          });

          console.log(_this.state);

          break;
        case "Last 7 Days":
          showReports = await reportsService.reloQuotes({
            reportStatus: "Last 7 Days"
          });

          data = showReports.recordsets[0];

          data.forEach((element, index, array) => {
            reloNames.push(element.reloNames);
            reloCount.push(element.NoofOrders);
          });

          _this.setState({
            chartData: update(_this.state.chartData, {
              labels: { $set: reloNames },
              datasets: { 0: { data: { $set: reloCount } } }
            })
          });

          console.log(_this.state);

          break;
      }
    });

    //console.log(this.state);
  }

  async reloQuotes() {
    const showreloQuotes = await reportsService.reloQuotes();
    let data = showreloQuotes.recordsets[0];
    let reloNames = [];
    let reloCount = [];

    data.forEach((element, index, array) => {
      reloNames.push(element.reloNames);
      reloCount.push(element.NoofOrders);
    });

    this.setState({
      chartData: update(this.state.chartData, {
        labels: { $set: reloNames },
        datasets: { 0: { data: { $set: reloCount } } }
      })
    });
  }

  async componentDidMount() {
    await this.chartColors();
    await this.datePicker();

    // Execute models real time thus re-rendering live data on the chart real time
    await this.reloQuotes();
  }

  render() {
    return (
      <div className="fluid-container">
        <div className="container">
          <h1>Reports</h1>
          <div className="row">
            <div className="daterangeContainer">
              <div
                id="daterangePicker"
                style={{
                  background: "#fff",
                  cursor: "pointer",
                  padding: "5px 10px",
                  border: "1px solid #ccc",
                  width: "100%"
                }}
              >
                <i className="fa fa-calendar" />
                &nbsp;
                <span /> <i className="fa fa-caret-down" />
              </div>
            </div>
          </div>
          <div className="row">
            <div className="col-md-12">
              <Bar
                data={this.state.chartData}
                height={800}
                options={{
                  maintainAspectRatio: false,
                  legend: {
                    display: false
                  },
                  scales: {
                    xAxes: [
                      {
                        ticks: {
                          beginAtZero: true,
                          autoSkip: false
                        },
                        scaleLabel: {
                          display: true
                        }
                      }
                    ]
                  },
                  title: {
                    display: true,
                    text: "Quotes",
                    fontSize: 16
                  },
                  plugins: {
                    datalabels: {
                      display: true,
                      color: "white"
                    }
                  }
                }}
                redraw
              />
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default Reportspage;

4

1 回答 1

2

所以你描述的问题是当组件重新渲染时数据被添加到你的组件状态中。在您提供的代码片段中,您不使用 React 中可以在重新渲染时触发的任何生命周期方法。而且我看不到任何其他应该在重新渲染时触发的钩子。因此,我找不到您的问题的任何来源。

但是,我可以看到其他可能使您更难调试的问题。解决这些问题可能会帮助您确定实际问题。在componentDidMount方法中,您调用函数的唯一目的是更新状态。这不是一个好的设计,因为它会强制组件在安装时立即重新渲染几次。

更好的设计是在构造函数中充分准备chartData-objekt。例如,您可以更改chartColors函数以将 chartData 对象作为参数,并返回添加了颜色的新对象。然后让你的构造函数看起来像这样:

constructor(props) {

   super(props);
   const chartDataWithoutColors = {
       labels: [],
       datasets: [
         {
           //label: "Quotes",
           data: [],
           backgroundColor: []
         }
       ]
     }

   const chartDataWithColor = this.chartColors(chartDataWithoutColors);

   this.state = {
     chartData: chartDataWithColor
   };
}

通过删除对您的不必要的调用,setState将使您的组件生活更简单,性能更高。当你简化了你的组件后,开始调试,一次删除一个非关键部分,并在你的问题消失时尝试确定。这应该足以找到错误。

祝你好运!

于 2018-09-21T07:54:52.710 回答