Skip to content

Commit 5fb4535

Browse files
authored
Merge pull request #1923 from wix/fix/CalendarList_performance
Fix/calendar list performance
2 parents ddabe09 + bdf6acc commit 5fb4535

File tree

2 files changed

+99
-117
lines changed

2 files changed

+99
-117
lines changed

src/calendar-list/index.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ class CalendarList extends Component<CalendarListProps, State> {
124124

125125
constructor(props: CalendarListProps) {
126126
super(props);
127-
128127
this.style = styleConstructor(props.theme);
129128

130129
const rows = [];
@@ -170,7 +169,6 @@ class CalendarList extends Component<CalendarListProps, State> {
170169
static getDerivedStateFromProps(_: CalendarListProps, prevState: State) {
171170
const rowClone = prevState.rows;
172171
const newRows = [];
173-
174172
for (let i = 0; i < rowClone.length; i++) {
175173
let val: XDate | string = prevState.texts[i];
176174
// @ts-expect-error
@@ -289,12 +287,27 @@ class CalendarList extends Component<CalendarListProps, State> {
289287
});
290288
};
291289

292-
renderItem = ({item}: any) => {
293-
const {calendarStyle, horizontal, calendarWidth, testID, ...others} = this.props;
290+
getMarkedDatesForItem(item?: any) {
291+
const {markedDates} = this.props;
292+
293+
if (markedDates) {
294+
if (item && item.getTime) {
295+
for (const [key, _] of Object.entries(markedDates)) {
296+
if (sameMonth(new XDate(key), new XDate(item))) {
297+
return markedDates;
298+
}
299+
}
300+
}
301+
}
302+
}
294303

304+
renderItem = ({item}: any) => {
305+
const {horizontal, calendarStyle, calendarWidth, testID, ...others} = this.props;
306+
// NOTE: now only 'item' and 'markedDates' change for the 3 calendar (item.getTime) items
295307
return (
296308
<CalendarListItem
297309
{...others}
310+
markedDates={this.getMarkedDatesForItem(item)}
298311
item={item}
299312
testID={`${testID}_${item}`}
300313
style={calendarStyle}

src/calendar-list/item.tsx

Lines changed: 82 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import PropTypes from 'prop-types';
2-
import memoize from 'memoize-one';
31
import XDate from 'xdate';
42

5-
import React, {Component} from 'react';
3+
import React, {useRef, useMemo, useContext} from 'react';
64
import {Text, View} from 'react-native';
75

86
import {Theme} from '../types';
9-
import {extractComponentProps} from '../componentUpdater';
10-
import {formatNumbers, sameMonth} from '../dateutils';
7+
import {formatNumbers} from '../dateutils';
8+
import {getCalendarDateString} from '../services';
119
import Calendar, {CalendarProps} from '../calendar';
1210
import styleConstructor from './style';
13-
import {getCalendarDateString} from '../services';
11+
import CalendarContext from '../expandableCalendar/Context';
1412

1513
export type CalendarListItemProps = CalendarProps & {
1614
item: any;
@@ -21,120 +19,91 @@ export type CalendarListItemProps = CalendarProps & {
2119
scrollToMonth?: (date: XDate) => void;
2220
};
2321

24-
type CalendarListItemState = {
25-
hideArrows: boolean;
26-
hideExtraDays: boolean;
27-
};
28-
29-
class CalendarListItem extends Component<CalendarListItemProps, CalendarListItemState> {
30-
static displayName = 'CalendarListItem';
31-
32-
static propTypes = {
33-
...Calendar.propTypes,
34-
item: PropTypes.any,
35-
calendarWidth: PropTypes.number,
36-
calendarHeight: PropTypes.number,
37-
horizontal: PropTypes.bool
38-
};
39-
40-
static defaultProps = {
41-
hideArrows: true,
42-
hideExtraDays: true
43-
};
44-
45-
style: any;
46-
47-
constructor(props: CalendarListItemProps) {
48-
super(props);
49-
50-
this.style = styleConstructor(props.theme);
51-
}
52-
53-
shouldComponentUpdate(nextProps: CalendarListItemProps) {
54-
const r1 = this.props.item;
55-
const r2 = nextProps.item;
56-
57-
return !sameMonth(r1, r2) || !!(r2.propBump && r2.propBump !== r1.propBump);
58-
}
59-
60-
onPressArrowLeft = (method: () => void, month: XDate) => {
61-
const {onPressArrowLeft, scrollToMonth} = this.props;
62-
const monthClone = month.clone();
63-
64-
if (onPressArrowLeft) {
65-
onPressArrowLeft(method, monthClone);
66-
} else if (scrollToMonth) {
67-
const currentMonth = monthClone.getMonth();
68-
monthClone.addMonths(-1);
69-
70-
// Make sure we actually get the previous month, not just 30 days before currentMonth.
71-
while (monthClone.getMonth() === currentMonth) {
72-
monthClone.setDate(monthClone.getDate() - 1);
22+
const CalendarListItem = React.memo((props: CalendarListItemProps) => {
23+
const {
24+
theme,
25+
item,
26+
scrollToMonth,
27+
horizontal,
28+
calendarHeight,
29+
calendarWidth,
30+
testID,
31+
style: propsStyle,
32+
headerStyle,
33+
onPressArrowLeft,
34+
onPressArrowRight
35+
} = props;
36+
const context = useContext(CalendarContext);
37+
38+
const style = useRef(styleConstructor(theme));
39+
const calendarStyle = useMemo(() => {
40+
return [
41+
{
42+
width: calendarWidth,
43+
minHeight: calendarHeight
44+
},
45+
style.current.calendar,
46+
propsStyle
47+
];
48+
}, [calendarWidth, calendarHeight, propsStyle]);
49+
50+
const _onPressArrowLeft = (method: () => void, month?: XDate) => {
51+
const monthClone = month?.clone();
52+
if (monthClone) {
53+
if (onPressArrowLeft) {
54+
onPressArrowLeft(method, monthClone);
55+
} else if (scrollToMonth) {
56+
const currentMonth = monthClone.getMonth();
57+
monthClone.addMonths(-1);
58+
59+
// Make sure we actually get the previous month, not just 30 days before currentMonth.
60+
while (monthClone.getMonth() === currentMonth) {
61+
monthClone.setDate(monthClone.getDate() - 1);
62+
}
63+
scrollToMonth(monthClone);
7364
}
74-
75-
scrollToMonth(monthClone);
7665
}
7766
};
7867

79-
onPressArrowRight = (method: () => void, month: XDate) => {
80-
const {onPressArrowRight, scrollToMonth} = this.props;
81-
const monthClone = month.clone();
82-
83-
if (onPressArrowRight) {
84-
onPressArrowRight(method, monthClone);
85-
} else if (scrollToMonth) {
86-
monthClone.addMonths(1);
87-
scrollToMonth(monthClone);
68+
const _onPressArrowRight = (method: () => void, month?: XDate) => {
69+
const monthClone = month?.clone();
70+
if (monthClone) {
71+
if (onPressArrowRight) {
72+
onPressArrowRight(method, monthClone);
73+
} else if (scrollToMonth) {
74+
monthClone.addMonths(1);
75+
scrollToMonth(monthClone);
76+
}
8877
}
8978
};
9079

91-
getCalendarStyle = memoize((width, height, style) => {
92-
return [{width, minHeight: height}, this.style.calendar, style];
93-
});
94-
95-
render() {
96-
const {
97-
item,
98-
horizontal,
99-
calendarHeight,
100-
calendarWidth,
101-
testID,
102-
style,
103-
headerStyle,
104-
onPressArrowLeft,
105-
onPressArrowRight,
106-
// @ts-expect-error
107-
context
108-
} = this.props;
109-
const calendarProps = extractComponentProps(Calendar, this.props);
110-
const calStyle = this.getCalendarStyle(calendarWidth, calendarHeight, style);
111-
112-
if (item.getTime) {
113-
return (
114-
<Calendar
115-
{...calendarProps}
116-
testID={testID}
117-
current={getCalendarDateString(item.toString())}
118-
style={calStyle}
119-
headerStyle={horizontal ? headerStyle : undefined}
120-
disableMonthChange
121-
onPressArrowLeft={horizontal ? this.onPressArrowLeft : onPressArrowLeft}
122-
onPressArrowRight={horizontal ? this.onPressArrowRight : onPressArrowRight}
123-
context={context}
124-
/>
125-
);
126-
} else {
127-
const text = formatNumbers(item.toString());
128-
129-
return (
130-
<View style={[{height: calendarHeight, width: calendarWidth}, this.style.placeholder]}>
131-
<Text allowFontScaling={false} style={this.style.placeholderText}>
132-
{text}
133-
</Text>
134-
</View>
135-
);
80+
if (item.getTime) {
81+
return (
82+
<Calendar
83+
hideArrows={true}
84+
hideExtraDays={true}
85+
{...props}
86+
testID={testID}
87+
current={getCalendarDateString(item.toString())}
88+
style={calendarStyle}
89+
headerStyle={horizontal ? headerStyle : undefined}
90+
disableMonthChange
91+
onPressArrowLeft={horizontal ? _onPressArrowLeft : onPressArrowLeft}
92+
onPressArrowRight={horizontal ? _onPressArrowRight : onPressArrowRight}
93+
context={context} // ???
94+
/>
95+
);
96+
} else {
97+
const text = formatNumbers(item.toString());
98+
return (
99+
<View style={[{height: calendarHeight, width: calendarWidth}, style.current.placeholder]}>
100+
<Text allowFontScaling={false} style={style.current.placeholderText}>
101+
{text}
102+
</Text>
103+
</View>
104+
);
136105
}
137-
}
138-
}
106+
});
139107

140108
export default CalendarListItem;
109+
CalendarListItem.displayName = 'CalendarListItem';

0 commit comments

Comments
 (0)