You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MUI X DatePicker:onDaySelect未返回指定Luxon DateTime类型问题

问题:MUI X DatePicker多选单日时onDaySelect返回Date而非Luxon DateTime类型

我想用MUI X DatePicker做一个可多选单日(非范围)的组件,传入的日期是Luxon的DateTime类型,但onDaySelect方法返回的却是Date类型(控制台输出已验证),导致isDaySelected方法里调用hasSame时直接报错——因为数组里的Date对象根本没有这个方法。想问这是我漏了配置,还是组件本身的bug?


组件代码

import React, {useCallback, useState} from "react";
import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider";
import {AdapterDateFns} from "@mui/x-date-pickers/AdapterDateFns";
import {PickersDay, StaticDatePicker} from "@mui/x-date-pickers";
import {Badge, TextField} from "@mui/material";
import {DateTime} from "luxon";

const SelectMultipleDates: React.FC = () => {

    const [selectedDates, setSelectedDates] = useState<DateTime[]>([]);

    const handleClickOnDay = useCallback((day: DateTime) => {
        console.log("is dateTime: " + (day instanceof DateTime));
        console.log("is Date: " + (day instanceof Date));
        setSelectedDates([...selectedDates, day]);
    }, [selectedDates]);

    const isDaySelected = useCallback((providedDay: DateTime) => {
        return selectedDates.some((value) => value.hasSame(providedDay, "day"));
    }, [selectedDates]);

    return (
        <LocalizationProvider dateAdapter={AdapterDateFns}>
            <StaticDatePicker
                displayStaticWrapperAs="desktop"
                openTo="day"
                value={DateTime.now()}
                onChange={() => console.log("nothing")}
                renderDay={(day: DateTime) => (
                    <PickersDay 
                        key={day.toString()}
                        day={day}
                        selected={isDaySelected(day)}
                        onDaySelect={(day: DateTime) => handleClickOnDay(day)}
                        outsideCurrentMonth={false}/>
                )}
                closeOnSelect={false}
                renderInput={(params) => <TextField {...params} />}
            />
        </LocalizationProvider>
    );
};

export default SelectMultipleDates;

控制台输出

is dateTime: false       SelectMultipleDates.tsx:13 
is Date: true            SelectMultipleDates.tsx:14

package.json内容

{
  "name": "mui-date-picker-test",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@date-io/date-fns": "^2.14.0",
    "@emotion/react": "^11.9.3",
    "@emotion/styled": "^11.9.3",
    "@mui/material": "^5.9.2",
    "@mui/x-date-pickers": "^5.0.0-beta.2",
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.5.2",
    "@types/luxon": "^3.0.0",
    "@types/node": "^16.11.46",
    "@types/react": "^18.0.15",
    "@types/react-dom": "^18.0.6",
    "date-fns": "^2.29.1",
    "luxon": "^3.0.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "typescript": "^4.7.4",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

解答

核心原因

这不是组件bug,是你选的适配器不对。你当前用的AdapterDateFns是和date-fns库绑定的适配器,它内部只会用原生Date对象处理日期,所以onDaySelect返回的必然是Date类型,和你导入的Luxon没关系。

两种解决办法

方法1:切换到Luxon适配器(推荐)

直接用适配Luxon的适配器,这样组件内部所有日期都会以Luxon DateTime类型返回,完全匹配你的需求。

首先安装依赖:

npm install @date-io/luxon@2.x @mui/x-date-pickers/AdapterLuxon

然后修改组件代码:

import React, {useCallback, useState} from "react";
import {LocalizationProvider} from "@mui/x-date-pickers/LocalizationProvider";
// 替换成Luxon专属适配器
import {AdapterLuxon} from "@mui/x-date-pickers/AdapterLuxon";
import {PickersDay, StaticDatePicker} from "@mui/x-date-pickers";
import {TextField} from "@mui/material";
import {DateTime} from "luxon";

const SelectMultipleDates: React.FC = () => {

    const [selectedDates, setSelectedDates] = useState<DateTime[]>([]);

    // 优化多选逻辑:点击已选中日期时移除它
    const handleClickOnDay = useCallback((day: DateTime) => {
        console.log("is dateTime: " + (day instanceof DateTime));
        console.log("is Date: " + (day instanceof Date));
        setSelectedDates(prev => 
            prev.some(d => d.hasSame(day, "day")) 
                ? prev.filter(d => !d.hasSame(day, "day")) 
                : [...prev, day]
        );
    }, []);

    const isDaySelected = useCallback((providedDay: DateTime) => {
        return selectedDates.some((value) => value.hasSame(providedDay, "day"));
    }, [selectedDates]);

    return (
        <LocalizationProvider dateAdapter={AdapterLuxon}>
            <StaticDatePicker
                displayStaticWrapperAs="desktop"
                openTo="day"
                value={DateTime.now()}
                onChange={() => console.log("nothing")}
                renderDay={(day: DateTime) => (
                    <PickersDay 
                        key={day.toString()}
                        day={day}
                        selected={isDaySelected(day)}
                        onDaySelect={(day: DateTime) => handleClickOnDay(day)}
                        outsideCurrentMonth={false}/>
                )}
                closeOnSelect={false}
                renderInput={(params) => <TextField {...params} />}
            />
        </LocalizationProvider>
    );
};

export default SelectMultipleDates;

方法2:手动转换Date为Luxon DateTime(临时方案)

如果不想切换适配器,可以在回调里把返回的Date对象转换成Luxon DateTime:

// 修改handleClickOnDay
const handleClickOnDay = useCallback((day: Date) => {
    const luxonDay = DateTime.fromJSDate(day);
    setSelectedDates(prev => 
        prev.some(d => d.hasSame(luxonDay, "day")) 
            ? prev.filter(d => !d.hasSame(luxonDay, "day")) 
            : [...prev, luxonDay]
    );
}, []);

// 同时修改renderDay里的类型转换
renderDay={(day: Date) => {
    const luxonDay = DateTime.fromJSDate(day);
    return (
        <PickersDay 
            key={luxonDay.toString()}
            day={day}
            selected={isDaySelected(luxonDay)}
            onDaySelect={(day: Date) => handleClickOnDay(day)}
            outsideCurrentMonth={false}/>
    );
}}

补充说明

MUI X DatePicker的日期类型完全由适配器决定:用AdapterDateFns就用Date,用AdapterLuxon就用Luxon DateTime,用AdapterMoment就用Moment对象。你之前导入了Luxon但没配对应适配器,所以组件根本不会用Luxon处理日期。


内容的提问来源于stack exchange,提问作者emaarco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 10:15:38