仅当子组件的值更改时,我才想更新它。 我有此代码:
<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需要大量时间来重新生成每一天的组件。 这是生成月份的示例:
当用户单击上午(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
答案 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/