🗓️

React DatePicker(day,week,month)

2024/07/13に公開1

月毎,週ごとを選択できるDatePickerの使い方がまとまっているといいなと思ったのでメモ
https://reactdatepicker.com/

注意

  • Nextjs,TS,Chakrauiを使用しています
  • デザインの部分は可読性のため削っています
  • cssのインポートをしないとぐちゃぐちゃなのが出てくる
import 'react-datepicker/dist/react-datepicker.css'
  • formatDateの関数はdate-fnsで作ってます

day

基本的なやつ
customInputを作成することで見た目を自由に変形できる
refを受け取れるようにforwardRedを使う

import React, { forwardRef } from 'react'

import { ChevronDownIcon } from '@chakra-ui/icons'
import { Button, Text } from '@chakra-ui/react'
import { startOfDay } from 'date-fns'
import ReactDatePicker from 'react-datepicker'

import { formatDateJpYMD } from '@/utils/formatTime'

import 'react-datepicker/dist/react-datepicker.css'

type CustomInputProps = {
  onClick: () => void
  startDate: Date
}

type DateSelectPickerProps = {
  setStartDate: React.Dispatch<React.SetStateAction<Date>>
  startDate: Date
}

const CustomInput = forwardRef<HTMLButtonElement, CustomInputProps>
(({ onClick, startDate }, ref) => (
  <Button
    ref={ref}
    onClick={onClick}
  >
    <Text>
      {formatDateJpYMD(startDate)}
    </Text>
    <ChevronDownIcon />
  </Button>
))
CustomInput.displayName = 'CustomInput'

const DateSelectPicker = ({ setStartDate, startDate }: DateSelectPickerProps) => {
  return (
    <ReactDatePicker
      customInput={<CustomInput startDate={startDate} onClick={() => {}} />}
      selected={startDate}
      onChange={(date) => setStartDate(startOfDay(date!))}
    />
  )
}

export default DateSelectPicker

week

選択した日から週の初めと終わりの日を計算する
dateには週の初めが入るようにして該当する週に選択マークをつける

isSameISOWeek(date, startDate) ? 'react-datepicker__day--selected' : ''

import React, { forwardRef } from 'react'

import { ChevronDownIcon } from '@chakra-ui/icons'
import { Button, HStack, Text } from '@chakra-ui/react'
import { isSameISOWeek, startOfDay } from 'date-fns'
import ReactDatePicker from 'react-datepicker'

import { formatDateJpMD, formatDateJpYMD } from '@/utils/formatTime'

import 'react-datepicker/dist/react-datepicker.css'

type CustomInputProps = {
  endDate: Date
  onClick: () => void
  startDate: Date
}

type WeekSelectPickerProps = {
  setStartDate: React.Dispatch<React.SetStateAction<Date>>
  startDate: Date
}

const CustomInput = forwardRef<HTMLButtonElement, CustomInputProps>(({ endDate, onClick, startDate }, ref) => (
  <Button
    ref={ref}
    onClick={onClick}
  >
    <HStack>
      <Text>
        {formatDateJpYMD(new Date(startDate))}
      </Text>
      <Text>
        ~
      </Text>
      <Text>
        {formatDateJpMD(endDate)}
      </Text>
    </HStack>
    <ChevronDownIcon/>
  </Button>
))
CustomInput.displayName = 'CustomInput'

const WeekSelectPicker = ({ setStartDate, startDate }: WeekSelectPickerProps) => {
  const monthEndDate = () => {
    const start = new Date(startDate)
    start.setDate(start.getDate() + 6)
    return start
  }

  const getStartOfWeek = (date: Date): Date => {
    const day = date.getDay()
    const diff = day === 0 ? -6 : 1 - day
    const startDate = new Date(date)
    startDate.setDate(date.getDate() + diff)
    const startOfWeek = startOfDay(startDate)
    return startOfWeek
  }

  return (
    <ReactDatePicker
      calendarStartDay={1}
      customInput={<CustomInput endDate={monthEndDate()} startDate={startDate} onClick={() => {}} />}
      dayClassName={(date: Date) => (isSameISOWeek(date, startDate) ? 'react-datepicker__day--selected' : '')}
      selected={startDate}
      onChange={(date) => setStartDate(getStartOfWeek(date!))}
    />
  )
}

export default WeekSelectPicker

month

ReactDatePickerにshowMonthYearPickerをつけるだけ

import React, { forwardRef } from 'react'

import { ChevronDownIcon } from '@chakra-ui/icons'
import { Button, Text } from '@chakra-ui/react'
import { startOfDay } from 'date-fns'
import ReactDatePicker from 'react-datepicker'

import { formatDateJpYM } from '@/utils/formatTime'

import 'react-datepicker/dist/react-datepicker.css'

type CustomInputProps = {
  onClick: () => void
  startDate: Date
}

type MonthSelectPickerProps = {
  setStartDate: React.Dispatch<React.SetStateAction<Date>>
  startDate: Date
}

const CustomInput = forwardRef<HTMLButtonElement, CustomInputProps>(({ onClick, startDate }, ref) => (
  <Button
    ref={ref}
    onClick={onClick}
  >
    <Text>
      {formatDateJpYM(startDate)}
    </Text>
    <ChevronDownIcon/>
  </Button>
))
CustomInput.displayName = 'CustomInput'

const MonthSelectPicker = ({ setStartDate, startDate }: MonthSelectPickerProps) => {
  return (
    <ReactDatePicker
      showMonthYearPicker
      customInput={<CustomInput startDate={startDate} onClick={() => {}} />}
      selected={startDate}
      onChange={(date) => setStartDate(startOfDay(date!))}
    />
  )
}

export default MonthSelectPicker

Discussion