Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Memo'd Android component to avoid re-rendering upstream which h…
…as 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)
- Loading branch information
1 parent
0ced69c
commit 069b2ca
Showing
1 changed file
with
71 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,80 @@ | ||
import React from "react"; | ||
import React, { useEffect, useState, memo } from "react"; | ||
import PropTypes from "prop-types"; | ||
import DateTimePicker from "@react-native-community/datetimepicker"; | ||
|
||
export class DateTimePickerModal extends React.PureComponent { | ||
static propTypes = { | ||
date: PropTypes.instanceOf(Date), | ||
isVisible: PropTypes.bool, | ||
onCancel: PropTypes.func.isRequired, | ||
onConfirm: PropTypes.func.isRequired, | ||
onHide: PropTypes.func, | ||
maximumDate: PropTypes.instanceOf(Date), | ||
minimumDate: PropTypes.instanceOf(Date), | ||
}; | ||
const DateTimePickerModal = memo(({ | ||
date, | ||
mode, | ||
isVisible, | ||
onCancel, | ||
onConfirm, | ||
onHide, | ||
...otherProps | ||
}) =>{ | ||
const [currentDate, setCurrentDate] = useState(date); | ||
const [currentMode, setCurrentMode] = useState(null); | ||
|
||
static defaultProps = { | ||
date: new Date(), | ||
isVisible: false, | ||
onHide: () => {}, | ||
}; | ||
useEffect(()=>{ | ||
if (isVisible && currentMode === null) { | ||
setCurrentMode(mode === "time" ? "time" : "date"); | ||
} else if (!isVisible) { | ||
setCurrentMode(null); | ||
} | ||
}, [isVisible, currentMode]); | ||
|
||
state = { | ||
currentMode: null, | ||
}; | ||
if (!isVisible || !currentMode) return null; | ||
|
||
currentDate = this.props.date; | ||
return ( | ||
<DateTimePicker | ||
{...otherProps} | ||
mode={currentMode} | ||
value={date} | ||
onChange={(event, date) => { | ||
if (event.type === "dismissed") { | ||
onCancel(); | ||
onHide(false); | ||
return; | ||
} | ||
let nextDate = date; | ||
if (mode === "datetime") { | ||
if (currentMode === "date") { | ||
setCurrentMode("time") | ||
setCurrentDate(new Date(date)); | ||
return; | ||
} else if (currentMode === "time") { | ||
const year = currentDate.getFullYear(); | ||
const month = currentDate.getMonth(); | ||
const day = currentDate.getDate(); | ||
const hours = date.getHours(); | ||
const minutes = date.getMinutes(); | ||
nextDate = new Date(year, month, day, hours, minutes); | ||
} | ||
} | ||
onConfirm(nextDate); | ||
onHide(true, nextDate); | ||
}} | ||
/> | ||
); | ||
}, | ||
(prevProps, nextProps) => | ||
prevProps.isVisible === nextProps.isVisible | ||
&& prevProps.date === nextProps.date | ||
); | ||
|
||
static getDerivedStateFromProps(props, state) { | ||
if (props.isVisible && state.currentMode === null) { | ||
return { currentMode: props.mode === "time" ? "time" : "date" }; | ||
} else if (!props.isVisible) { | ||
return { currentMode: null }; | ||
} | ||
return null; | ||
} | ||
DateTimePickerModal.propTypes = { | ||
date: PropTypes.instanceOf(Date), | ||
isVisible: PropTypes.bool, | ||
onCancel: PropTypes.func.isRequired, | ||
onConfirm: PropTypes.func.isRequired, | ||
onHide: PropTypes.func, | ||
maximumDate: PropTypes.instanceOf(Date), | ||
minimumDate: PropTypes.instanceOf(Date), | ||
}; | ||
|
||
handleChange = (event, date) => { | ||
if (event.type === "dismissed") { | ||
this.props.onCancel(); | ||
this.props.onHide(false); | ||
return; | ||
} | ||
if (this.props.mode === "datetime") { | ||
if (this.state.currentMode === "date") { | ||
this.currentDate = new Date(date); | ||
this.setState({ currentMode: "time" }); | ||
return; | ||
} else if (this.state.currentMode === "time") { | ||
const year = this.currentDate.getFullYear(); | ||
const month = this.currentDate.getMonth(); | ||
const day = this.currentDate.getDate(); | ||
const hours = date.getHours(); | ||
const minutes = date.getMinutes(); | ||
this.currentDate = new Date(year, month, day, hours, minutes); | ||
} | ||
} else { | ||
this.currentDate = date; | ||
} | ||
this.props.onConfirm(this.currentDate); | ||
this.props.onHide(true, this.currentDate); | ||
}; | ||
DateTimePickerModal.defaultProps = { | ||
date: new Date(), | ||
isVisible: false, | ||
onHide: () => {}, | ||
}; | ||
|
||
render() { | ||
const { isVisible, date, ...otherProps } = this.props; | ||
const { currentMode } = this.state; | ||
if (!isVisible || !currentMode) return null; | ||
return ( | ||
<DateTimePicker | ||
{...otherProps} | ||
mode={currentMode} | ||
value={date} | ||
onChange={this.handleChange} | ||
/> | ||
); | ||
} | ||
} | ||
export {DateTimePickerModal}; |