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 modal won't close when I press "ok". It also takes two presses of "cancel" to actually cancel out and close the modal. Here's a gif of what that 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
// Imports: Dependencies
import React, { useState } 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);
// alert('Android Visible:' + 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 {
// Event Type: Set Date
if (event.type === 'set') {
// React Hook: Set From Date
setDate(date);
// // React Props: onChange
// props.onChange(date);
// React Hook: Toggle Android
toggleAndroid((androidModalVisible: boolean) => !androidModalVisible);
}
// Event Type: Dismissed
else if (event.type === 'dismissed') {
// Do Nothing
// React Hook: Toggle Android
toggleAndroid((androidModalVisible: boolean) => !androidModalVisible);
}
}
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 {
return (
<RNDateTimePicker
mode="date"
display={props.mode}
value={date}
onChange={(event: any, date: Date) => selectDate(event, date)}
/>
)
}
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>
{/* <Icon name="ios-arrow-forward" size={22} style={styles.arrowForward}/> */}
</TouchableOpacity>
{androidModalVisible === false ? renderAndroidPicker(): null}
<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: '#CFD3D9',
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;