🗓️
React DatePicker(day,week,month)
月毎,週ごとを選択できるDatePickerの使い方がまとまっているといいなと思ったのでメモ
注意
- 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
PortalのパターンでReact Hook Formとの連携にチャレンジしてみました