NextJS中react-calendar日期重复及当日无法选择问题求助
问题分析与修复方案
问题概述
使用NextJS、TypeScript、TailwindCSS及react-calendar开发日历组件时,遇到两个核心问题:
- 选择日期范围时,下月除已选日期及跨月日期外的所有日期重复显示
- 无法选择当日、当月及当年的日期
问题原因及修复方案
1. 日期重复显示问题
原因:tileContent逻辑错误,当日期不在选中范围的月份时,错误返回日期数字,导致react-calendar原生渲染的日期与自定义内容叠加显示。
修复:调整tileContent判断逻辑,仅在日期属于当前显示月份、未被选中且未过期时返回自定义内容:
tileContent={({ date, view, activeStartDate }) => { if (view === 'month') { // 判断日期是否属于当前显示的月份 const isCurrentMonth = date.getMonth() === activeStartDate.getMonth() && date.getFullYear() === activeStartDate.getFullYear(); if (selectedDates === null || isDateSelected(date)) { return null; } else if (date < new Date(new Date().setHours(0, 0, 0, 0))) { return null; } else if (!isCurrentMonth) { return null; } else { return ( <div className=""> {date.getDate()} </div> ); } } return null; }}
2. 无法选择当日及近期日期问题
原因:tileDisabled中使用date <= new Date(),会将当日未过的时间段也判定为不可选,导致整个当日无法选择。
修复:将当日时间部分清零后再比较,确保当日可被选中:
tileDisabled={({ date }) => { const today = new Date(); today.setHours(0, 0, 0, 0); return date < today; }}
完整修正后的核心代码片段
import React, { useState } from 'react'; import Calendar from 'react-calendar'; import ReservationModal from './ReservationModal'; import '../calendar/CusCalendar.css'; const CusCalendar: React.FC = () => { const [selectedDates, setSelectedDates] = useState<Date[] | Date | null>(null); const [showCalculation, setShowCalculation] = useState(false); const [showReservationPopup, setShowReservationPopup] = useState(false); const [currentMonth, setCurrentMonth] = useState(new Date()); const startDate = Array.isArray(selectedDates) ? selectedDates[0] : null; const endDate = Array.isArray(selectedDates) ? selectedDates[1] : null; const pricePerNight = 100; const nights = startDate && endDate ? Math.floor((endDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24)) : 0; const totalPrice = nights * pricePerNight; const isDateSelected = (date: Date) => { return startDate && endDate && date >= startDate && date <= endDate; }; const handleDateChange = (date: Date | Date[]) => { if (!startDate || (startDate && endDate)) { setSelectedDates(Array.isArray(date) ? date : [date]); } else { if (Array.isArray(date) && date[0] >= startDate) { setSelectedDates(date); } else { setSelectedDates(Array.isArray(date) ? date : [date]); } } }; const handleCalculate = () => { if (startDate && endDate) { const numberOfNights = Math.floor( (endDate.getTime() - startDate.getTime()) / (1000 * 3600 * 24) ); const totalPrice = numberOfNights * pricePerNight; setShowCalculation(true); } }; const handleClearDates = () => { setSelectedDates(null); }; const handleReserve = () => { if (startDate && endDate) { setShowReservationPopup(true); } }; const handleReserveClick = () => { setShowReservationPopup(true); }; const handleMonthChange = (newMonth: Date) => { setCurrentMonth(newMonth); }; return ( <div className="text-start border-4 rounded-[30px] solid border-[#ebebeb] w-[478px] h-full"> {!showCalculation ? ( <div> <div className="text-[28px] font-bold text-[#313131] leading-normal uppercase pl-7 pt-7 pb-3">SELECT CHECK-IN DATE</div> <div className="text-[18px] font-normal leading-normal text-[#969696] pl-7 pb-7">Add your travel dates for exact pricing</div> </div> ) : null} <div className="mx-7"> {!showCalculation ? ( <Calendar onChange={handleDateChange as any} selectRange={true} tileContent={({ date, view, activeStartDate }) => { if (view === 'month') { const isCurrentMonth = date.getMonth() === activeStartDate.getMonth() && date.getFullYear() === activeStartDate.getFullYear(); if (selectedDates === null || isDateSelected(date)) { return null; } else if (date < new Date(new Date().setHours(0, 0, 0, 0))) { return null; } else if (!isCurrentMonth) { return null; } else { return ( <div className=""> {date.getDate()} </div> ); } } return null; }} tileDisabled={({ date }) => { const today = new Date(); today.setHours(0, 0, 0, 0); return date < today; }} /> ) : null} </div> {/* 剩余部分代码保持不变 */} </div> ); }; export default CusCalendar;
补充说明
- 日期重复问题:通过
activeStartDate判断当前显示月份,确保自定义内容只渲染当前月份的日期,避免与react-calendar原生跨月日期渲染重复 - 日期选择限制问题:将当日时间清零后比较,确保当日及之后的日期均可正常选择
内容的提问来源于stack exchange,提问作者userunknown
相关产品推荐
相关产品推荐

