2

我有一个带有子图表组件的主要组件。在连接到 websocket 时,主组件会更新子图表组件的状态。但是,这不会重绘。但是,当我单击图表时,会出现标签,当我再次单击时,值会与标签一起出现。

主.js:

import IO from 'socket.io-client';
import React from "react";

import { Switch, Route } from 'react-router-dom';
import { Chart } from "./Chart";

let ftse100Tickers = require('./ftse_100_tickers.json');
let randomInt = Math.floor(Math.random() * ftse100Tickers.tickers.length);

/**
 * Main application component which contains
 */
export class Main extends React.Component {
    componentWillMount() {
        this.socket = IO(location.protocol + "//" + document.domain + ":" + location.port);
        this.socket.on("connect", (() => this.connect()));
        this.socket.on("disconnect", (() => this.disconnect()));
        this.socket.on("initial data", ((data) => this.createInitialChart(data)))
    }

    connect(){
        this.setState({status: 'connected'});
        this.socket.emit("get initial data", this.state.ticker);
    }

    disconnect(){
        this.setState({status: 'disconnected'})
    }

    createInitialChart(data){
        let tempErrorChart= this.state.errorChart;
        for (let row of data){
            tempErrorChart.labels.push(row.time_stamp);
            tempErrorChart.datasets[0].data.push(row.error);
        }
        this.setState({errorChart: tempErrorChart});
    }


    constructor(props){
        super(props);
        this.state = {
            errorChart: {
                labels: [],
                datasets: [
                    {
                        label: 'Error',
                        data: [],
                    },
                ]
            },
            status: 'disconnected',
            ticker : ftse100Tickers.tickers[randomInt],
            twitter : ftse100Tickers.twitter[randomInt]
        }
    }
    render() {
        return (
            <div className="row">
                <div className="row">
                    <div className="col-lg-6">
                        <div className="card border-0">
                            <div className="card-body">
                                <Chart chart={this.state.errorChart}/>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

图表组件如下:

图表.js

import { Line } from "react-chartjs-2"
import React from "react";

/*
 * General charting component used for rendering charts
 */
export class Chart extends React.Component {

    render() {
        return (
            <Line data={this.props.chart} options={{}}/>
        )
    }
}
4

2 回答 2

6

我看到一个问题,那就是您在this.state.errorChart调用之前没有在 errorChart 更新时更改对象引用setState。即使您将新项目推送到其属性,对象甚至内部数组引用也不会改变,并且如果 Line 组件执行一些道具检查它是否应该重新呈现自己,它仍然通过接收相同的引用来计算,什么都没有已更改,无需重新渲染。

现在这只是我的假设,但无论哪种方式,一旦这些对象即将被修改,在创建新状态时始终创建新对象是一个好习惯。这允许在shouldComponentUpdate方法中或在使用对象(状态)引用时进行快速的对象(状态)引用比较,PureComponent这反过来又使确定是否重新渲染组件变得更容易和更高效。另一方面,如果您仍然使用相同的引用,则必须对新旧状态进行深度比较,从长远来看,这肯定会更加昂贵且非常脆弱。

有关如何正确更新状态的示例如下:

createInitialChart(data) {
  const errorChart = this.state.errorChart

  const newErrorChart = {
    ...errorChart
  }

  newErrorChart.labels = [...errorChart.labels, data.map(row => row.time_stamp)]
  newErrorChart.datasets[0].data = [
    ...errorChart.datasets[0].data,
    data.map(row => row.error)
  ]

  this.setState({ errorChart: newErrorChart })
}

编辑: 通过查看组件的shouldComponentUpdate实现 - ChartComponent,可以清楚地看到,关于如何使Line重新渲染有多种选择,例如。通过给Line组件提供redraw={true}道具。不过,上述过程通常仍然是确保重新渲染的最安全方法。

于 2018-03-19T12:56:22.720 回答
0

您可能需要 componentWillReceiveProps(nextProps, nextState)。您可以将此处的旧状态与新状态进行比较,并相应地更新状态。

请像这样设置initialState:

constructor(props){
 super(props);
 this.state = {errorChart: {...}}; //your initial values here.
}

然后,

componentWillReceiveProps(nextProps, nextState){
 if(this.state.errorChart !== nextState.errorChart){
   let tempErrorChart = {...this.state.errorChart};
    for (let row of data){
        tempErrorChart.labels.push(row.time_stamp);
        tempErrorChart.datasets[0].data.push(row.error);
    }
    this.setState({errorChart: tempErrorChart});
 }
}
于 2018-03-19T12:13:31.053 回答