[英]react render for loop run twice
I am trying to make simple calendar with moment.我正在尝试用时刻制作简单的日历。 It load perfect on first time but when click on previous or next my for loop in render run twice what can be the issue
它第一次加载完美,但是当单击上一个或下一个我的 for 循环在渲染中运行两次时可能是什么问题
My project
https://stackblitz.com/edit/react-ts-itbzcd My project
https://stackblitz.com/edit/react-ts-itbzcd
public render() {
let day = this.props.date
for (let i = 0; i < 7; i++) {
this.days.push(
<Day key={day.toString()} date={day.date()} />
);
day = day.clone();
day.add(1, "day");
}
console.log(this.days)
return (
<tr key={this.days[0]}>
{this.days}
</tr>
);
}
Complete Calendar
component:完整的
Calendar
组件:
import moment = require('moment');
import * as React from 'react'
import { DayNames, Week } from '.'
import styles from './Calendar.module.scss'
interface ICalendarProps {
}
interface ICalendarState {
dateObject: moment.Moment
showYearTable: boolean
}
export class Calendar extends React.Component<ICalendarProps, ICalendarState> {
constructor(props: ICalendarProps) {
super(props)
this.state = {
dateObject: moment(),
showYearTable: false
}
this.onNext = this.onNext.bind(this)
this.onPrev = this.onPrev.bind(this)
}
public render(): React.ReactElement<ICalendarProps> {
const datePicker =
<div className="datepicker-days">
<table className={styles.table}>
<thead>
<tr>
<th><span className="ms-Icon ms-Icon--ChevronLeft" title="Previous Month" onClick={this.onPrev}>Previous</span></th>
<th className={styles["picker-switch"]} data-action="pickerSwitch" colSpan={5} title="Select Month">
{this.month()}{" "} {this.year()}
</th>
<th><span className="ms-Icon ms-Icon--ChevronRight" title="Next Month" onClick={this.onNext}>Next</span></th>
</tr>
<tr>
<DayNames />
</tr>
</thead>
<tbody>
{this.renderWeeks()}
</tbody>
</table>
</div>
return (
<div className="datepicker">
{datePicker}
</div>
)
}
private month = () => {
return this.state.dateObject.format('MMMM')
}
private year = () => {
return this.state.dateObject.format("Y");
};
private onPrev = () => {
this.setState({
dateObject: this.state.dateObject.subtract(1, this.state.showYearTable === true ? "year" : "month")
});
};
private onNext = () => {
this.setState({
dateObject: this.state.dateObject.add(1, this.state.showYearTable === true ? "year" : "month")
});
};
private renderWeeks() {
let weeks = [];
let date = this.state.dateObject.clone().startOf("month").add("w").day("Sunday");
let done = false;
let count = 0;
let monthIndex = date.month();
while (!done) {
weeks.push(
<Week key={date.toString()} date={date.clone()} />
)
date.add(1, "w");
done = count++ > 2 && monthIndex !== date.month();
monthIndex = date.month();
}
return weeks
}
}
I got your problem.我得到了你的问题。 You are having this problem because of how you are setting the
key
prop of the Week
component on the renderWeeks
function.你有,因为你是如何设置的这个问题
key
的道具的Week
上的组件renderWeeks
功能。 1 week repeats from a month to another, so when you change the month, 2 Week
s components end with the same key
prop. 1 周从一个月到另一个月重复,因此当您更改月份时, 2
Week
的组件以相同的key
属性结束。 React, when is rerendering your component, see that and recycle that component. React,何时重新渲染您的组件,请查看并回收该组件。
Doing something like this solves your problem:这样做可以解决您的问题:
private renderWeeks() {
let weeks = [];
let date = this.state.dateObject.clone().startOf("month").add("w").day("Sunday");
let done = false;
let count = 0;
let monthIndex = date.month();
while (!done) {
weeks.push(
<Week key={Math.floor(Math.random() * 10000)} date={date.clone()} />
)
date.add(1, "w");
done = count++ > 2 && monthIndex !== date.month();
monthIndex = date.month();
}
return weeks
}
But it could decrease your rerendering performance, you need to deal with your Calendar
component to avoid him to rerender the first week or you can clean all of your calendar states with a loading component (bad UX).但这可能会降低您的重新渲染性能,您需要处理您的
Calendar
组件以避免他在第一周重新渲染,或者您可以使用加载组件(糟糕的用户体验)清理所有日历状态。 There are many alternatives.有很多选择。
My solution would be storing the weeks on the Calendar
component state, then update it with just the new weeks.我的解决方案是将周数存储在
Calendar
组件状态中,然后仅使用新周数对其进行更新。
The loop in Week - execute 4 times, so keys in days duplicate.周中的循环 - 执行4次,因此天数重复。
[0,1,2,3,4,5,6] then [0,1,2,3,4,5,6] then [0,1,2,3,4,5,6] then [0,1,2,3,4,5,6]
[0,1,2,3,4,5,6] 然后 [0,1,2,3,4,5,6] 然后 [0,1,2,3,4,5,6] 然后 [0] ,1,2,3,4,5,6]
So 21 days have duplicated key.所以21天有重复的密钥。
Ok, optimalized solution and basically works.好的,优化的解决方案,基本上有效。 (the problem appears when jumping between months) - do you need to write a condition that will check the number of days in the month and based on it stop the loops?
(在月份之间跳转时会出现问题) - 您是否需要编写一个条件来检查当月的天数并根据它停止循环? You can solve this like this - loop in loop:
您可以像这样解决这个问题 - 循环循环:
private renderWeeks() {
let weeks = [];
let date = this.state.dateObject.clone().startOf("month").add("w").day("Sunday");
let count = 0;
let monthIndex = date.month();
let day = date;
for (let i = 0; i < 4; i++) {
weeks.push(<Week key={date.toString()} date={date.clone()} />)
date.add(1, "w");
monthIndex = date.month();
for (let j = 0; j < 7; j++) {
weeks.push(<Day key={weeks.length} date={day.date()} />);
day = day.clone();
day.add(1, "day");
}
}
return weeks
}
And in Day.tsx在Day.tsx
import * as React from 'react'
interface IDayProps {
date: number
}
export class Day extends React.Component<IDayProps, {}> {
public render() {
return (
<td>{this.props.date}</td>
);
}
}
You also can give for key :你也可以给 key :
<Day key={Math.random()} date={day.date()} />
It works optimally - the problem is:它以最佳方式工作 - 问题是:
It looks like the problem is in your renderWeeks()
function in Calendar.tsx
.看起来问题出在
Calendar.tsx
中的renderWeeks()
函数中。
In the line done = count++ > 2 && monthIndex !== date.month();
在
done = count++ > 2 && monthIndex !== date.month();
, try moving the ++
to the front of count
( ++count
) so that it is incremented BEFORE being compared to 2
. , 尝试将
++
移动到count
( ++count
) 的前面,以便在与2
进行比较之前增加它。 Or reduce 2
to 1
.或者减少
2
到1
。
StackBlitz wasn't working for me when I tried altering anything so I wasn't able to play around with it (pretty cool site though).当我尝试改变任何东西时,StackBlitz 对我不起作用,所以我无法使用它(虽然很酷的网站)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.