[英]react render for loop run twice
我正在嘗試用時刻制作簡單的日歷。 它第一次加載完美,但是當單擊上一個或下一個我的 for 循環在渲染中運行兩次時可能是什么問題
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>
);
}
完整的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
}
}
我得到了你的問題。 你有,因為你是如何設置的這個問題key
的道具的Week
上的組件renderWeeks
功能。 1 周從一個月到另一個月重復,因此當您更改月份時, 2 Week
的組件以相同的key
屬性結束。 React,何時重新渲染您的組件,請查看並回收該組件。
這樣做可以解決您的問題:
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
}
但這可能會降低您的重新渲染性能,您需要處理您的Calendar
組件以避免他在第一周重新渲染,或者您可以使用加載組件(糟糕的用戶體驗)清理所有日歷狀態。 有很多選擇。
我的解決方案是將周數存儲在Calendar
組件狀態中,然后僅使用新周數對其進行更新。
周中的循環 - 執行4次,因此天數重復。
[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]
所以21天有重復的密鑰。
好的,優化的解決方案,基本上有效。 (在月份之間跳轉時會出現問題) - 您是否需要編寫一個條件來檢查當月的天數並根據它停止循環? 您可以像這樣解決這個問題 - 循環循環:
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
}
在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>
);
}
}
你也可以給 key :
<Day key={Math.random()} date={day.date()} />
它以最佳方式工作 - 問題是:
看起來問題出在Calendar.tsx
中的renderWeeks()
函數中。
在done = count++ > 2 && monthIndex !== date.month();
, 嘗試將++
移動到count
( ++count
) 的前面,以便在與2
進行比較之前增加它。 或者減少2
到1
。
當我嘗試改變任何東西時,StackBlitz 對我不起作用,所以我無法使用它(雖然很酷的網站)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.