简体   繁体   English

为什么子组件会更新而不重新渲染Reactjs

[英]Why is the child component updating but not re-render Reactjs

I have a main component with a child chart component. 我有一个带有子图表组件的主要组件。 On connecting to a websocket, the main component updates the state of the child chart component. 连接到Websocket时,主要组件将更新子图表组件的状态。 This however does not redraw. 但是,这不会重绘。 When I click on the chart however, the labels appear, and when I click again, the values appear with the labels. 但是,当我单击图表时,将显示标签,而当我再次单击时,值将与标签一起显示。

Main.js: 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>
        )
    }
}

The chart component is as so: 图表组件是这样的:

Chart.js 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={{}}/>
        )
    }
}

I see one problem and that is you are not changing object references in this.state.errorChart upon errorChart update before you call setState . 我看到一个问题,那就是在调用setState之前,在errorChart更新时您没有在this.state.errorChart更改对象引用。 Even though you push to its properties new items, the object and even the inner array references do not change, and if the Line component does some props checking on whether it should rerender itself or not, it figures by receiving still the same references that nothing has changed and there is no need to rerender. 即使您将其新属性推入其属性,该对象甚至内部数组引用也不会更改,并且如果Line组件对是否应重新呈现自身进行了一些支持,则它会通过接收仍然相同的引用来表示数字已经更改,因此无需重新渲染。

Now this was just my assumption, but either way it is a good practice to always create new objects while creating new state once those objects are about to be modified. 现在,这只是我的假设,但是无论哪种方式,当这些对象即将被修改时, 始终在创建新对象的同时创建新状态是一个好习惯。 This allows for fast object (state) references comparisons in shouldComponentUpdate methods or while using PureComponent which in turn makes it easier and more performant to determine whether to rerender the component or not. 这允许在shouldComponentUpdate方法中或在使用PureComponent进行快速的对象(状态)引用比较,从而可以更轻松,更PureComponent地确定是否重新渲染组件。 On the other hand, if you would use the same references still, you would have to implement deep comparison of the old and the new state, which is definitely more expensive and very fragile in the long run. 另一方面,如果仍然使用相同的引用,则必须对旧状态和新状态进行深入比较,从长远来看,这肯定会更昂贵且非常脆弱。

Example on how to correctly update the state follows: 有关如何正确更新状态的示例如下:

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 })
}

Edit: By looking at the component's shouldComponentUpdate implementation - ChartComponent , It can be clearly seen, that there are multiple options on how to make the Line rerender, eg. 编辑:通过查看组件的shouldComponentUpdate实现-ChartComponent ,可以清楚地看到,关于如何使Line重新渲染有多个选项。 by giving redraw={true} prop to the Line component. 通过为Line组件提供redraw={true}属性。 The procedure above is generally still the safest way to ensure rerender though. 上面的过程通常仍然是确保重新提交的最安全方法。

You might need componentWillReceiveProps(nextProps, nextState). 您可能需要componentWillReceiveProps(nextProps,nextState)。 You can compare the old state here with the new state and update the state accordingly. 您可以在此处将旧状态与新状态进行比较,并相应地更新状态。

Please set the initialState like so: 请像这样设置initialState:

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

then, 然后,

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});
 }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM