Skip to content

Commit 069b2ca

Browse files
authored
feat: Memo'd Android component to avoid re-rendering upstream which has a bug (#453)
* Refactored the Android component to use hooks and memo'd it so that it only renders the underlying DateTimePicker once (or on date change)
1 parent 0ced69c commit 069b2ca

File tree

1 file changed

+71
-67
lines changed

1 file changed

+71
-67
lines changed

src/DateTimePickerModal.android.js

Lines changed: 71 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,80 @@
1-
import React from "react";
1+
import React, { useEffect, useState, memo } from "react";
22
import PropTypes from "prop-types";
33
import DateTimePicker from "@react-native-community/datetimepicker";
44

5-
export class DateTimePickerModal extends React.PureComponent {
6-
static propTypes = {
7-
date: PropTypes.instanceOf(Date),
8-
isVisible: PropTypes.bool,
9-
onCancel: PropTypes.func.isRequired,
10-
onConfirm: PropTypes.func.isRequired,
11-
onHide: PropTypes.func,
12-
maximumDate: PropTypes.instanceOf(Date),
13-
minimumDate: PropTypes.instanceOf(Date),
14-
};
5+
const DateTimePickerModal = memo(({
6+
date,
7+
mode,
8+
isVisible,
9+
onCancel,
10+
onConfirm,
11+
onHide,
12+
...otherProps
13+
}) =>{
14+
const [currentDate, setCurrentDate] = useState(date);
15+
const [currentMode, setCurrentMode] = useState(null);
1516

16-
static defaultProps = {
17-
date: new Date(),
18-
isVisible: false,
19-
onHide: () => {},
20-
};
17+
useEffect(()=>{
18+
if (isVisible && currentMode === null) {
19+
setCurrentMode(mode === "time" ? "time" : "date");
20+
} else if (!isVisible) {
21+
setCurrentMode(null);
22+
}
23+
}, [isVisible, currentMode]);
2124

22-
state = {
23-
currentMode: null,
24-
};
25+
if (!isVisible || !currentMode) return null;
2526

26-
currentDate = this.props.date;
27+
return (
28+
<DateTimePicker
29+
{...otherProps}
30+
mode={currentMode}
31+
value={date}
32+
onChange={(event, date) => {
33+
if (event.type === "dismissed") {
34+
onCancel();
35+
onHide(false);
36+
return;
37+
}
38+
let nextDate = date;
39+
if (mode === "datetime") {
40+
if (currentMode === "date") {
41+
setCurrentMode("time")
42+
setCurrentDate(new Date(date));
43+
return;
44+
} else if (currentMode === "time") {
45+
const year = currentDate.getFullYear();
46+
const month = currentDate.getMonth();
47+
const day = currentDate.getDate();
48+
const hours = date.getHours();
49+
const minutes = date.getMinutes();
50+
nextDate = new Date(year, month, day, hours, minutes);
51+
}
52+
}
53+
onConfirm(nextDate);
54+
onHide(true, nextDate);
55+
}}
56+
/>
57+
);
58+
},
59+
(prevProps, nextProps) =>
60+
prevProps.isVisible === nextProps.isVisible
61+
&& prevProps.date === nextProps.date
62+
);
2763

28-
static getDerivedStateFromProps(props, state) {
29-
if (props.isVisible && state.currentMode === null) {
30-
return { currentMode: props.mode === "time" ? "time" : "date" };
31-
} else if (!props.isVisible) {
32-
return { currentMode: null };
33-
}
34-
return null;
35-
}
64+
DateTimePickerModal.propTypes = {
65+
date: PropTypes.instanceOf(Date),
66+
isVisible: PropTypes.bool,
67+
onCancel: PropTypes.func.isRequired,
68+
onConfirm: PropTypes.func.isRequired,
69+
onHide: PropTypes.func,
70+
maximumDate: PropTypes.instanceOf(Date),
71+
minimumDate: PropTypes.instanceOf(Date),
72+
};
3673

37-
handleChange = (event, date) => {
38-
if (event.type === "dismissed") {
39-
this.props.onCancel();
40-
this.props.onHide(false);
41-
return;
42-
}
43-
if (this.props.mode === "datetime") {
44-
if (this.state.currentMode === "date") {
45-
this.currentDate = new Date(date);
46-
this.setState({ currentMode: "time" });
47-
return;
48-
} else if (this.state.currentMode === "time") {
49-
const year = this.currentDate.getFullYear();
50-
const month = this.currentDate.getMonth();
51-
const day = this.currentDate.getDate();
52-
const hours = date.getHours();
53-
const minutes = date.getMinutes();
54-
this.currentDate = new Date(year, month, day, hours, minutes);
55-
}
56-
} else {
57-
this.currentDate = date;
58-
}
59-
this.props.onConfirm(this.currentDate);
60-
this.props.onHide(true, this.currentDate);
61-
};
74+
DateTimePickerModal.defaultProps = {
75+
date: new Date(),
76+
isVisible: false,
77+
onHide: () => {},
78+
};
6279

63-
render() {
64-
const { isVisible, date, ...otherProps } = this.props;
65-
const { currentMode } = this.state;
66-
if (!isVisible || !currentMode) return null;
67-
return (
68-
<DateTimePicker
69-
{...otherProps}
70-
mode={currentMode}
71-
value={date}
72-
onChange={this.handleChange}
73-
/>
74-
);
75-
}
76-
}
80+
export {DateTimePickerModal};

0 commit comments

Comments
 (0)