我正在创建一个日历组件,其中包含2个带有FlatList
的视图。每个视图都与一个不同的数据源关联。具体来说,“视图1”将显示一个月中的所有日子,而“视图2”将显示一周中的所有日子。
Link to video demo, button of year is for view switching
为简单起见,每个月/周视图由日期表示为更大数组中的数组项。
例如,month
数组中的每个项目都是一个月内的唯一数据。大小为12的数组每个月都有12个唯一的日期。然后,每个Date()
对象都会向下传递给我的子组件,以进行正确的渲染。此特定month
数组的结果是一个完整的12个月日历列表。
注意:为了提高性能,我的子组件将仅呈现current month -1
,current month
和current month +1
,其他所有月份将在用户滚动离开时有条件地呈现。 / p>
[
...
Wed May 30 2018 21:51:47 GMT+0800 (+08),
Sat Jun 30 2018 21:51:47 GMT+0800 (+08),
Mon Jul 30 2018 21:51:47 GMT+0800 (+08),
...
]
视图2(周视图)也是如此。除了现在我的数据包含一个月中所有星期的一周中唯一的几天。
在实施这种方法之前,我尝试从子组件中破解一些东西。例如,当用户单击按钮切换视图时,它将沿道具向下传递,并带有当前的Date()
对象,以通知子项有条件地渲染其他视图。这基本上是在View
和FlatList
之间切换。嵌套FlatList
是一个坏主意,因为两个列表都朝着同一方向滚动。
更不用说我的日历组件涉及到选定的月份。我实现的另一种解决方案是通过从month
中窃取索引,仅对两个视图使用keyExtractor
数组。例如,一旦用户jumps
从一个月到另一个月,我就会立即为列表重新建立索引,但是不久我意识到这是一种反模式,只会导致更多问题。
注意:我已经在所有孩子中实施了
shouldComponentUpdate
组件。因此,仅滚动1个View应该没有问题,大小 数据源完全不会受影响,因为只有更改-1
,0
和+1
月份的发生情况将得到反映。的 我的组件的瓶颈仅在切换视图时才会发生。
简而言之,现在我求助于当前的解决方案,其中在array
中有2个不同视图的2个不同数据源(FlatList
)。我有一个按钮供用户在模式之间切换。问题在于,每次通过从onViewableItemsChanged
调用此道具FlatList
重新实例化视图时,都要花费一些时间来切换模式(设置状态),这涉及一些复杂的计算。有更好的方法吗?
代码(父母)
renderCalendarList = () => {
return (
<FlatList
pageSize={1}
horizontal={true}
pagingEnabled={true}
scrollEnabled={true}
keyExtractor={this.keyExtractor}
ref={(c) => this.calendarList = c}
getItemLayout={this.getItemLayout}
renderItem={this.renderCalendarComponent}
onViewableItemsChanged={this.onViewableItemsChanged}
data={(this.state.weekMode ? this.state.weekRows : this.state.rows)} />
)
}
switchView = () => {
this.setState({ weekMode: !this.state.weekMode });
// next week is going to be month view
if (this.state.weekMode) {
const mYClone = this.state.monthYears.slice(0);
const selectedDay = DateUtils.formatDateInMY(this.props.selectedDay);
for (let i = 0; i < mYClone.length; i++) {
if (selectedDay === mYClone[i]) {
this.setState({ currentMonth: this.props.selectedDay })
this.calendarList.scrollToIndex({ animated: false, index: i });
}
}
} else { // next week is going to be week view
const rowClone = this.state.weekRows.slice(0);
for (let i = 0; i < rowClone.length; i++) {
if (isSameWeek(rowClone[i], this.props.selectedDay)) {
this.setState({ currentMonth: rowClone[i] });
this.calendarList.scrollToIndex({ animated: false, index: i });
}
}
}
}
代码(儿童)
render() {
const { container, monthContainer, weekContainer } = styles;
const { currentMonth, firstDay, style, weekMode } = this.props;
if (!weekMode) {
const days = DateUtils.populateMonth(currentMonth, firstDay);
const weeks = [];
while (days.length) {
weeks.push(this.renderWeek(days.splice(0, 7), weeks.length));
}
return (
<View style={[container, style]}>
<View style={[monthContainer]}>{weeks}</View>
</View>
)
} else {
const startDay = subDays(currentMonth, 3); // focus on middle
const endDay = addDays(startDay, 6)
const days = eachDay(startDay, endDay, 1);
const daysToRender = [];
days.forEach((day, dayID) => {
daysToRender.push(this.renderDay(day, dayID))
});
return (
<View style={style}>
<View style={[weekContainer]}>
{daysToRender}
</View>
</View>
)
}
}