React ChartJS阻止新数据在重绘后添加到状态中吗?

时间:2018-09-18 18:42:41

标签: reactjs chart.js react-chartjs react-state-management

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

但是,当图表被重绘并重新呈现时,它被添加到我不想要的状态上。我只想重新呈现请求的新数据,然后将其添加到图表中的旧数据上。

实际上我之前使用香草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;

1 个答案:

答案 0 :(得分: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的不必要的调用,您可以使组件的寿命更简单,更高效。简化组件后,请一次删除一个非关键部件来开始调试,并在问题消失时尝试确定故障原因。这应该足以找到该错误。

祝你好运!