我有一个带有子图表组件的主要组件。在连接到websocket时,主要组件更新子图表组件的状态。但是这不会重绘。然而,当我点击图表时,会出现标签,当我再次点击时,这些值会显示标签。
Main.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>
)
}
}
图表组件如下:
chart.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={{}}/>
)
}
}
答案 0 :(得分:5)
我看到一个问题,那就是在您调用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 重新呈现,例如。通过向{strong>行组件提供redraw={true}
道具。上述程序通常仍然是确保重新投降的最安全方式。
答案 1 :(得分: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});
}
}