I am attempting to create a date picker that appears when a field with an icon and the current date in string format is clicked.
I am using React Native, React Hook Form, and @react-native-community/datetimepicker.
Fortunately, I came across an interesting solution on an unrelated question:
Here is how I implemented it:
const MyComponent = () => {
const { userData } = useContext(UserDataContext)
const [isPickerOpen, setIsPickerOpen] = useState(false)
const parsedBirthday = (userData && userData.birthday && userData.birthday.toDate()) || new Date()
const [birthday, setBirthday] = useState(parsedBirthday)
// Validation schema
const schema = yup.object({
birthday: yup.date(),
})
const { control, handleSubmit, errors } = useForm({resolver: yupResolver(schema)})
const onSubmit = async (data: any) => {
console.log(data)
}
const datePickerHandler = (selectedDate: Date) => {
const currentDate = selectedDate || birthday
if (Platform.OS === 'android') setIsPickerOpen(false)
setBirthday(currentDate)
}
const showDatePicker = () => {
setIsPickerOpen(true)
}
return (
<View style={styles.fieldContainer}>
<Text style={styles.helper}>Birthday</Text>
<TouchableHighlight activeOpacity={0.6} underlayColor="#DDDDDD" onPress={showDatePicker} style={styles.birthday}>
<>
<Icon name="calendar-edit" size={32} color={colors.black} />
<Controller
control={control}
render={({ onChange, onBlur, value }) => (
<TextInput
style={styles.birthdayText}
value={birthday.toLocaleDateString()}
editable={false}
pointerEvents="none"
onTouchStart={() => showDatePicker()}
/>
)}
name="birthdayString"
defaultValue={birthday.toLocaleDateString() || new Date().toLocaleDateString()}
/>
</>
</TouchableHighlight>
{/* Date picker */}
{isPickerOpen && (
<Controller
control={control}
render={({ onChange, onBlur, value }) => (
<>
<View>
<DateTimePicker
minimumDate={new Date(1901, 0, 1)}
maximumDate={new Date()}
value={value}
mode="date"
display="default"
onChange={(event, value) => {
datePickerHandler(value)
}}
/>
</View>
</>
)}
name="birthday"
defaultValue={birthday}
/>
)}
<Text style={styles.errorText}>{errors?.birthday}</Text>
</View>
)
This implementation is challenging because the picker is unmounted when the values are submitted, requiring a TextInput component to hold the value.
I am curious if there is a better approach, as I have some concerns:
- Converting a string to a date, then back to a string, and then back to a date for submission could complicate things, especially for internationalization with .toLocaleDateString.
- onTouchStart only works with touch devices, not with mice, which could be an issue for Chromebooks.