You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

@mui/x-date-pickers DesktopDatePicker问题:过往日期无法显示

解决MUI DesktopDatePicker间歇性过往日期空白问题

我在React项目中使用Material-UI的@mui/x-date-pickers组件(具体是DesktopDatePicker),但偶尔打开日历后,过往日期会显示为空白而非预期的数字,该问题间歇性出现,暂未发现明确规律。

组件代码如下:

import React, { useState } from 'react'
import { Typography } from '@mui/material'
import { AdapterMoment } from '@mui/x-date-pickers/AdapterMoment'
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'
import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker'
import moment from 'moment'
import { Control, Controller } from 'react-hook-form'

const TimezoneDatePicker = ({
  name,
  control,
  rules,
  onChangeCallback,
  styles,
  inputVariant,
  onBlurCallback,
  disabled,
  disableFuture = false
}) => {
  const [open, setOpen] = useState(false)
  const handleOpen = () => {
    if (!disabled) {
      setOpen(true)
    }
  }
  const handleClose = () => {
    setOpen(false)
  }
  return (
    <>
      <Controller
        name={name}
        control={control}
        rules={rules}
        render={({ field: { onChange, value } }) => {
          const parsedValue = value ? moment(value) : null
          return (
            <LocalizationProvider dateAdapter={AdapterMoment}>
              <DesktopDatePicker
                closeOnSelect
                format='MM-DD-YYYY'
                open={open}
                onClose={handleClose}
                value={parsedValue ? parsedValue : null}
                {...(!disableFuture && { minDate: moment() })}
                disabled={disabled}
                timezone='UTC'
                disableFuture={disableFuture}
                key={name}
                onChange={(v: any) => {
                  onChange(v ? v.toISOString() : null)
                  onChangeCallback && onChangeCallback(v)
                }}
                onAccept={v => {
                  handleClose()
                  onBlurCallback && onBlurCallback(v)
                }}
                slotProps={{
                  textField: {
                    placeholder: 'Select Date',
                    fullWidth: true,
                    variant: inputVariant
                  },
                  inputAdornment: {
                    onClick: handleOpen
                  }
                }}
                sx={{ ...styles }}
              />
            </LocalizationProvider>
          )
        }}
      />
    </>
  )
}
export default TimezoneDatePicker

问题截图:
日历空白截图

可能的解决方向

  • 提升LocalizationProvider层级:当前LocalizationProvider嵌套在Controllerrender回调里,每次组件重渲染都会重新初始化日期适配器,容易导致状态不稳定。建议把它移到组件外部,比如表单顶层或者全局入口处,确保整个应用只初始化一次适配器。

  • 统一时区处理逻辑:组件设置了timezone='UTC',但minDate用的是moment()(默认本地时区),时区不匹配可能引发日期计算错误。把minDate改成moment.utc(),保持时区统一。

  • 缓存moment实例避免不必要重渲染:在render回调里每次创建新的moment对象,会触发组件频繁重渲染。用useMemo缓存解析后的日期和最小日期:

    const parsedValue = useMemo(() => value ? moment(value) : null, [value]);
    const minDate = useMemo(() => disableFuture ? null : moment.utc(), [disableFuture]);
    
  • 检查版本兼容性:确认moment@mui/x-date-pickersAdapterMoment的版本是否匹配,版本不兼容是这类间歇性问题的常见诱因。可以对照MUI官方文档查看推荐的依赖版本。

  • 优化组件key的使用:虽然用name作为key一般没问题,但如果存在动态修改name的场景,可能导致组件异常卸载/挂载。确保key的唯一性和稳定性,或者尝试移除key(如果没有必要)。

调试技巧

  • 用React DevTools Profiler追踪重渲染:记录组件的渲染次数和触发时机,看空白出现时是否有异常的重渲染,或者日期相关props是否出现异常值。

  • 打印关键日期值:在render回调里打印parsedValueminDate和传入的value,观察空白出现时这些值是否有效(比如是否为无效moment对象、时区是否正确)。

  • 复现场景测试:尝试快速开关日历、切换系统时区、修改系统时间,看能否稳定复现问题,缩小排查范围。

  • 隔离外部因素:临时注释掉自定义样式、回调函数等非核心代码,看问题是否消失,排除外部代码干扰。

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

火山引擎 最新活动