FormikとReact Datepickerを使って日付選択フォームを作る

Formikで作っているフォームに、カレンダーから日付選択できるinputフォームを追加したかったのでReact Datepickerと組み合わせることにした。

今回は時間選択もできるようにしたかったので、DateTimePickerというコンポーネントを作成。

ユーザが日付を入力した場合はpropsで渡されたonChangeを実行するようにしておく。

// components/DateTimePicker.tsx
import 'react-datepicker/dist/react-datepicker.css'

import React, { useState } from 'react'
import DatePicker from 'react-datepicker'

type Props = {
  name: string
  className?: string
  onChange?: (date: Date) => void
}

export const DateTimePicker = ({ className, onChange }: Props) => {
  const [startDate, setStartDate] = useState(new Date())

  const handleChange = (date: Date) => {
    setStartDate(date)
    onChange && onChange(date)
  }

  return (
    <DatePicker
      name={name}
      className={className}
      dateFormat="yyyy-MM-dd HH:mm"
      showTimeSelect
      selected={startDate}
      onChange={handleChange}
    />
  )
}

これで呼び出し元でonChangeが呼ばれた際に、setFieldValueでFormikのstateを更新すればカレンダーでの日付選択が実現できる。

// pages/form.tsx
import { Form, Formik, FormikHelpers } from 'formik'
import { DateTimePicker } from '@/components/DateTimePicker'

const FormPage = () => {
  return (
    <Formik
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={onSubmit}
    >
      {({ setFieldValue }: {
        setFieldValue: FormikHelpers<typeof initialValues>['setFieldValue']
      }) => (
        <Form>
          <label htmlFor="datetime">DateTime</label>
          <DateTimePicker
            name="datetime"
            onChange={(date: Date) => {
              setFieldValue('targetDateTime', date)
            }}
          />
        </Form>
      )}
    </Formik>
  )
}

export default FormPage