How to use @react-native-community/datetimepicker with React Hook Form?

Viewed 3135

I try to make a date picker that appears when clicking on a field with an icon and the current date in string format.

I use React Native, React Hook Form and @react-native-community/datetimepicker.

By chance I found an intersting answser there on an unrelated question: https://stackoverflow.com/a/61929764/9927519

I implemented it like that:

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 one is a bit hard due to the fact that the picker is unmounted when the values are submitted. Then, we need a TextInput component to hold the value.

I wonder if there is a better approach. I have some little concerns:

  • I convert a string into a date, then into string, then I will need to convert it back into a date when submiting... Actually .toLocaleDateString will make submiting very complex. This could be an issue for internationalization.
  • onTouchStart is not working with a mouse, only with touch devices. That could be an issue with chromebooks.
0 Answers
Related