I'm having an issue with the Android Picker from the React Native Datetime Picker library. This is also my first time using Typescript, but I can't figure out why my Android Picker requires me to press "ok" twice". It also takes two presses of "cancel" to actually cancel out and close the modal. Here's a gif of what issue looks like.
To keep track of the modal, I'm using a React Hook with the state as androidModalVisible. This is also my first time using functional components and React Hooks, so I'm not sure if there is some lifecycle issue I'm not noticing from the androidModalVisible React Hook?
DatePicker.tsx
The Line {androidModalVisible === false ? renderAndroidPicker(): null}
is where I render and don't render the modal with androidModalVisible
// Imports: Dependencies
import React, { useState, useEffect } from 'react';
import { Dimensions, Platform, StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import RNDateTimePicker from '@react-native-community/datetimepicker';
import Modal from 'react-native-modal';
import moment from 'moment';
// Screen Dimensions
const { height, width } = Dimensions.get('window');
// TypeScript: Types
interface Props {
title: string;
mode: 'calendar' | 'spinner' | 'default';
onChange: (date: Date) => any;
}
// Component: Date Picker
const DatePicker = (props: Props) => {
// React Hooks: State
const [ modalVisible, toggle ] = useState(false);
const [ androidModalVisible, toggleAndroid ] = useState(false);
const [ date, setDate ] = useState(new Date());
// Toggle Modal
const toggleModal = () => {
try {
// Check Platform (Android)
if (Platform.OS === 'android') {
// React Hook: Toggle Android
toggleAndroid((androidModalVisible: boolean) => !androidModalVisible);
}
// Check Platform (iOS)
if (Platform.OS === 'ios') {
// React Hook: Toggle Modal
toggle((modalVisible: boolean) => !modalVisible);
}
}
catch (error) {
console.log(error);
}
};
// Select Date
const selectDate = (event: any, date: Date) => {
try {
// Check Platform: Android
if (Platform.OS === 'android') {
// Event Type: Set Date
if (event.type === 'set') {
// React Hook: Set From Date
setDate(date);
// React Hook: Toggle Android
toggleAndroid(false);
// React Props: onChange
props.onChange(date);
}
// Event Type: Dismissed
if (event.type === 'dismissed') {
// React Hook: Toggle Android
toggleAndroid(false);
}
}
// Check Platform: Android
if (Platform.OS === 'ios') {
setDate(date);
// React Props: onChange
props.onChange(date);
}
}
catch (error) {
console.log(error);
}
};
// Render iOS Picker
const renderIOSPicker = () => {
try {
return (
<RNDateTimePicker
mode="date"
value={date}
onChange={(event: any, date: Date) => selectDate(event, date)}
/>
)
}
catch (error) {
console.log(error);
}
};
// Render Android Picker
const renderAndroidPicker = () => {
try {
if (androidModalVisible === true) {
return (
<RNDateTimePicker
mode="date"
display={props.mode}
value={date}
onChange={(event: any, date: Date) => selectDate(event, date)}
/>
)
}
else {
// Do Nothing
}
}
catch (error) {
console.log(error);
}
};
return (
<View style={styles.container}>
<View style={styles.inputTitleContainer}>
<Text style={styles.inputTitle}>{props.title}</Text>
</View>
<TouchableOpacity onPress={() => toggleModal()} style={styles.fieldTextContainer}>
<Text style={styles.fieldText} numberOfLines={1}>{date ? moment(date).format('MMM Do, YYYY') : 'Select'}</Text>
</TouchableOpacity>
<View>
{androidModalVisible === true ? renderAndroidPicker(): null}
</View>
<Modal isVisible={modalVisible} style={styles.modal}>
<View style={styles.modalContainer}>
<View style={styles.pickerHeaderContainer}>
<TouchableOpacity onPress={() => toggleModal()} >
<Text style={styles.doneText}>Done</Text>
</TouchableOpacity>
</View>
<View style={styles.pickerContainer}>
{renderIOSPicker()}
</View>
</View>
</Modal>
</View>
);
}
// Styles
const styles = StyleSheet.create({
container: {
display: 'flex',
width: width - 32,
marginLeft: 16,
marginRight: 16,
justifyContent: 'center',
},
modal: {
margin: 0,
},
modalContainer: {
height: '100%',
alignItems: 'center',
justifyContent: 'flex-end',
},
pickerHeaderContainer: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
height: 40,
width: width,
backgroundColor: '#FAFAF8',
borderColor: '#7D7D7D',
borderBottomWidth: StyleSheet.hairlineWidth,
},
pickerContainer: {
height: 220,
width: width,
backgroundColor: 'white',
},
doneText: {
fontFamily: 'System',
color: '#007AFF',
fontWeight: '600',
fontSize: 17,
marginRight: 16,
},
stateContainer: {
alignItems: 'center',
width: 75,
borderColor: '#7D7D7D',
borderBottomWidth: StyleSheet.hairlineWidth,
},
inputTitleContainer: {
width: 75,
marginBottom: 4,
},
inputTitle: {
color: '#7D7D7D',
borderColor: '#7D7D7D',
fontSize: 10,
fontWeight: '600',
textTransform: 'uppercase',
},
fieldTextContainer: {
height: 40,
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 4,
borderColor: '#7D7D7D',
borderBottomWidth: StyleSheet.hairlineWidth,
},
fieldText: {
width: width - 32 - 20,
fontFamily: 'System',
fontSize: 17,
fontWeight: '400',
color: '#000000',
alignSelf: 'center',
},
arrowForward: {
color: 'black',
opacity: .3,
marginRight: 7,
},
});
// Exports
export default DatePicker;