this.props,nextProp和nextState的值相同会导致错误的呈现

时间:2018-12-04 09:24:42

标签: reactjs rendering

仅当子组件的值更改时,我才想更新它。 我有此代码:

<Container fluid>
                <Row>
                    <Col md={2}>NameMonth + year</Col>
                    <Col md={10}>
                        <div className="vacationMonthDiv text-left">
                            {arrDays.map((item, index) => { // arrDays contains a list of moment of the actual month generated
                                return <Day day={this.state.calendar[numDays[index]]} mouseDown={this.clickDownVacation} key={"fullDay" + item.toString()} /> //state.calendar contains a list of object with a moment, 2 booleans (morning and afternoon) and an id
                            })}
                        </div>
                    </Col>
                </Row>
            </Container>

日间组件(使用PureComponent,但是我之前尝试使用shouldComponentUpdate()(将代码放入注释中):

export default class Day extends PureComponent {

/*shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
}*/

render() {
    this.props.day.date.locale('fr');
    var jour = this.props.day.date.format("ddd");
    var jourSemaine = this.props.day.date.format("DD");
    jour = jour.charAt(0).toUpperCase() + jour.slice(1);
    var isoDay = this.props.day.date.isoWeekday();
    return (
        <div className={isoDay === 7 ? "inline-block vacationLastOfWeek" : "inline-block"} key={"fullDay" + this.props.day.id} >
        <div className="vacationDayName text-center" key={"nameDay" + this.props.day.id}>{jour}</div>
            <div className="vacationDayNumber text-center" key={"numDay" + this.props.day.id}>{jourSemaine}</div>
            <div className={isoDay >= 6 || this.props.day.date.isFerie() ? "vacationHalfDay vacationMorning text-center cursor-normal vacationPublicHoliday" : "vacationHalfDay vacationMorning text-center cursor-pointer"} onMouseDown={() => this.props.mouseDown(this.props.day.id, true)} >
                {this.props.day.isMorningSelected ? <MaterialIcon icon="close" color="red" /> : <div> {isoDay >= 6 || this.props.day.date.isFerie() ? "W" : "M"}</div>}
        </div>
            <div className={isoDay >= 6 || this.props.day.date.isFerie() ? "vacationHalfDay vacationAfternoon text-center cursor-normal vacationPublicHoliday" : "vacationHalfDay vacationAfternoon text-center cursor-pointer"} onMouseDown={() => this.props.mouseDown(this.props.day.id, false)} >
                {this.props.day.isAfternoonSelected ? <MaterialIcon icon="close" color="red" /> : <div>{isoDay >= 6 || this.props.day.date.isFerie() ? "W" : "A"}</div>}
        </div>
    </div>
    );
}
}

现在,每天生成的代码正在运行。在生成一整年的报告时,react需要大量时间来重新生成每一天的组件。 这是生成月份的示例:

A generated month (january 2018)

当用户单击上午(M)或下午(A)时,将出现一个图标,表明已选中该图标。 但是,当用户单击时,每个组件都在重新渲染,这导致响应变慢。

做一些测试,我发现在我的Day组件中使用shouldcomponentupdate()时,nextState,nextProp和实际状态完全相同,导致比较结果为假。

仅当值更改时,如何比较这些值以激活渲染?

编辑:这是clickDownVacation:

clickDownVacation = (index, isMorning) => {
    var array = this.state.calendar;
    if (!array[index].date.isFerie() && array[index].date.isoWeekday() < 6) {
    if (isMorning) array[index].isMorningSelected = !array[index].isMorningSelected;
    else array[index].isAfternoonSelected = !array[index].isAfternoonSelected;

    this.setState({
        calendar: array
        });
    }
}

编辑2 :以下是复制品:Codebox

1 个答案:

答案 0 :(得分:1)

更改对象内的值时,对该对象的引用不会更改。 React对它的道具进行了浅层比较,以查看是否应该重新渲染。它只会检查道具是否已更改,而不会检查道具中是否有更改。

对于数组或对象,它仅检查“此数组或对象是否相同”,而不是“此数组/对象是否包含相同的值”

对于您的代码,您必须更改clickDownVacation

clickDownVacation = (index, isMorning) => {
  let array = ...this.state.calendar;
  let day = array[index]
  if (!day.date.isFerie() && day.date.isoWeekday() < 6) {
    array = [...array] // create a new array, containing the old values of array
    if (isMorning) {
      day = { // create a new 'day' object
        ...day, // copy all the old values of day into this new object
        isMorningSelected: !day.isMorningSelected;
      }
    }
    else {
      day = { // create a new 'day' object
        ...day, // copy all the old values of day into this new object
        isAfternoonSelected: !day.isAfternoonSelected;
      }
    }
    array[index] = day
    this.setState({
      calendar: array
      });
    }
  }
}

由于“数组”是一个新数组,而“日期”是一个新对象,因此react可以将其与旧值进行比较,并且会发现引用是不同的,因此可以重新渲染

关于“不变性”的一个很好的指南,解释了这个问题,是https://daveceddia.com/react-redux-immutability-guide/