I want to achieve that when the user clicks on a day, the selected day is saved in the state. However, I have the problem that when the month changes, the previously selected day is also saved in the state along with the currently selected month. When I log the onSelect event to the console and change the month, I receive 2 Dayjs objects.
Here's a Sandbox link: https://codesandbox.io/s/antd-reproduction-template-forked-0ihci4?file=/index.tsx
The code:
const [selectedDays, setSelectedDays] = React.useState<Dayjs[]>([])
console.log(selectedDays)
const dateCellRender = (value: Dayjs) => {
// give selected days a different color
if (selectedDays.some(day => day.isSame(value, 'day'))) {
return (
<div className=" h-28 m-1 rounded hover:bg-blue-100 bg-blue-200 transition-all" >
{value.date()}
</div>
)
} else {
return (
<div className=" h-28 rounded border-t hover:bg-blue-100 transition-all">
{value.date()}
</div>
)
}
};
return <div className='m-10'><Calendar value={undefined} onSelect={(e) => setSelectedDays(prev => {
// if the day is already selected, remove it from the array of selected days with isSame
if (prev.some(day => day.isSame(e, 'day'))) {
return prev.filter(day => !day.isSame(e, 'day'))
} else {
return [...prev, e]
}
})} fullCellRender={dateCellRender} /></div>
};
I tried to use different props like onChange onSelect, onChange, etc.. but there are always 2 console logs. I expected that there is no new selection when I change the month.
You need to define additional state variable that would keep the state of the selected date in the calendar. You can assign it by default to the current date with by just creating dayjs
object
const [selectedDays, setSelectedDays] = React.useState<Dayjs[]>([]);
// this is a new state variable
const [calendarDate, setCalendarDate] = React.useState<Dayjs>(dayjs());
Then what you have to do is just check if the month
or year
changed in onSelect
handler. I checked that this one is also called when you use the select for month and year.
What you have to do in that check, is just clearing your selectedDays
state by assigning empty array to it and do not execute the function further by using return statement in that if block. That way every time you change month or the year, you won't have any selected days.
onSelect
function code:
onSelect={(e) => {
// this is the new if statement that clears the state when month or year changes
if (!calendarDate.isSame(e, 'month') || !calendarDate.isSame(e, 'year')) {
setCalendarDate(e);
setSelectedDays([]);
return;
}
setSelectedDays((prev) => {
// if the day is already selected, remove it from the array of selected days with isSame
if (prev.some((day) => day.isSame(e, "day"))) {
return prev.filter((day) => !day.isSame(e, "day"));
} else {
return [...prev, e];
}
})
}