React+MUI DatePicker受控为ISO字符串时,外部清空按钮失效问题
问题描述
- 使用MUI DatePicker组件,将受控值设为ISO字符串格式
- 输入未完成的日期(如
01/MM/YYYY)后,点击外部清空按钮将受控值设为null,文本框内容未被清空 - 两种正常情况:
- 输入完整日期(如
01/01/2000)后点击清空按钮,可正常清空文本框 - 将受控值改为luxon DateTime对象时,清空功能正常
- 输入完整日期(如
代码示例
import { useState } from "react"; import { DateTime } from "luxon"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { Button } from "@mui/material"; export default function App() { const [startOpen, setStartOpen] = useState(false); const [val, setVal] = useState(DateTime.now().toISODate()); return ( <> <div className="App"> <LocalizationProvider dateAdapter={AdapterLuxon}> <DatePicker open={startOpen} onClose={() => setStartOpen(false)} sx={{ flex: 1 }} slotProps={{ field: { clearable: true, onClear: () => {}, onError: () => {}, }, textField: { onClick: () => setStartOpen(true), }, }} onChange={(v) => { setVal(v); }} onError={() => {}} value={DateTime.fromISO(val)} /> </LocalizationProvider> </div> <Button onClick={() => { setVal(null); console.log(val); }} > Clear </Button> </> ); }
问题原因
核心问题在于状态类型不统一以及DateTime.fromISO(null)的处理逻辑:
- 初始状态
val是ISO字符串,但onChange回调传入的v是luxon DateTime对象,导致val的类型在交互中会在字符串和对象间切换 - 输入不完整日期时,DatePicker的
onChange不会触发(输入值无法解析为有效日期),此时val仍为之前的有效ISO字符串 - 点击清空按钮设置
val = null后,DateTime.fromISO(null)会返回无效的DateTime对象,DatePicker处理无效对象时,不会自动清空输入框的临时文本
解决方案
方案一:统一状态类型(推荐)
始终使用luxon DateTime对象作为受控值,避免类型切换带来的解析问题:
import { useState } from "react"; import { DateTime } from "luxon"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { Button } from "@mui/material"; export default function App() { const [startOpen, setStartOpen] = useState(false); // 初始状态直接使用DateTime对象 const [val, setVal] = useState(DateTime.now()); return ( <> <div className="App"> <LocalizationProvider dateAdapter={AdapterLuxon}> <DatePicker open={startOpen} onClose={() => setStartOpen(false)} sx={{ flex: 1 }} slotProps={{ field: { clearable: true, onClear: () => setVal(null), onError: () => {}, }, textField: { onClick: () => setStartOpen(true), }, }} onChange={(v) => { setVal(v); }} onError={() => {}} value={val} /> </LocalizationProvider> </div> <Button onClick={() => { setVal(null); }} > Clear </Button> </> ); }
方案二:保留ISO字符串状态,处理null转换
如果必须使用ISO字符串作为状态,修改value属性的转换逻辑,确保val为null时传入null而非无效DateTime对象:
// 修改DatePicker的value属性 value={val ? DateTime.fromISO(val) : null}
内容的提问来源于stack exchange,提问作者Rob Allen
相关产品推荐
相关产品推荐

