如何让MUI DateTimePicker仅在点击Accept时触发onAccept?
问题:MUI DateTimePicker 仅在点击Accept按钮时触发onAccept
以下是我使用的ResponsiveDateTimePicker组件代码:
import React from 'react' import { Stack, Typography } from '@mui/material' import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker' import { renderTimeViewClock } from '@mui/x-date-pickers/timeViewRenderers' import dayjs, { Dayjs } from 'dayjs' interface ResponsiveDateTimePickerProps { value: Dayjs | null maxDateTime: Dayjs | null minDateTime: Dayjs | null disabled?: boolean label?: string onAccept: (date: Dayjs | null) => void } const ResponsiveDateTimePicker: React.FunctionComponent< ResponsiveDateTimePickerProps > = ({ value, maxDateTime, minDateTime, disabled, label, onAccept }) => { type textFieldSizes = 'small' | 'medium' | undefined type actionBarOptions = 'today' | 'accept' const dateTimePickerProps = { viewRenderers: !label ? { hours: renderTimeViewClock, minutes: renderTimeViewClock, seconds: renderTimeViewClock, } : undefined, value, maxDateTime: maxDateTime || undefined, minDateTime: minDateTime || undefined, onAccept: (date: unknown) => { if (dayjs.isDayjs(date)) { onAccept(date as Dayjs) } else { onAccept(null) } }, format: 'DD MMMM YYYY, h:mm a', disabled, slotProps: { actionBar: { actions: ['today' as actionBarOptions, 'accept' as actionBarOptions], sx: { padding: 0 }, }, textField: () => ({ size: 'small' as textFieldSizes, InputProps: { placeholder: value ? '' : 'Forever', sx: { height: '40px', }, slotProps: { input: { sx: { height: '21px !important', fontSize: '14px !important', padding: '8.5px 30px !important', }, }, }, }, }), }, } return ( <Stack direction="row" alignItems="center"> {label && ( <Typography variant="subtitle1" sx={{ minWidth: '120px' }} paddingRight={0} > {label} </Typography> )} <DateTimePicker {...dateTimePickerProps} /> </Stack> ) } export default ResponsiveDateTimePicker
当前组件的选择流程:
- 用户点击选择器显示区域
- 选择日期
- 选择小时(可切换上午/下午)
- 选择分钟(可切换上午/下午)
现在遇到的问题:选择完分钟后,组件会自动触发onAccept函数,把这一步当作确认操作。但我需要只有用户主动点击Accept按钮时才调用onAccept,同时允许用户返回修改小时、日期等选项,不打断操作流程。
解决方案
核心思路是:用内部临时状态存储用户的选择过程,关闭自动确认逻辑,仅在Accept按钮点击时同步结果给父组件。
修改后的完整代码:
import React, { useState } from 'react' import { Stack, Typography } from '@mui/material' import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker' import { renderTimeViewClock } from '@mui/x-date-pickers/timeViewRenderers' import dayjs, { Dayjs } from 'dayjs' interface ResponsiveDateTimePickerProps { value: Dayjs | null maxDateTime: Dayjs | null minDateTime: Dayjs | null disabled?: boolean label?: string onAccept: (date: Dayjs | null) => void } const ResponsiveDateTimePicker: React.FunctionComponent<ResponsiveDateTimePickerProps> = ({ value, maxDateTime, minDateTime, disabled, label, onAccept }) => { // 内部临时状态,存储用户选择过程中的日期值 const [tempValue, setTempValue] = useState<Dayjs | null>(value) // 自定义Accept按钮的点击逻辑 const handleAcceptClick = () => { onAccept(tempValue) } // 自定义Today按钮的点击逻辑 const handleTodayClick = () => { const today = dayjs() setTempValue(today) onAccept(today) } return ( <Stack direction="row" alignItems="center"> {label && ( <Typography variant="subtitle1" sx={{ minWidth: '120px' }} paddingRight={0}> {label} </Typography> )} <DateTimePicker viewRenderers={!label ? { hours: renderTimeViewClock, minutes: renderTimeViewClock, seconds: renderTimeViewClock, } : undefined} value={tempValue} maxDateTime={maxDateTime || undefined} minDateTime={minDateTime || undefined} // 关闭选择后自动触发确认的逻辑 onAccept={() => {}} // 选择后不自动关闭弹窗,允许用户返回修改 closeOnSelect={false} // 实时更新内部临时状态,不触发父组件的onAccept onChange={(newValue) => setTempValue(newValue)} format="DD MMMM YYYY, h:mm a" disabled={disabled} slotProps={{ actionBar: { // 自定义ActionBar按钮,替换默认的点击逻辑 actions: [ { label: 'Today', onClick: handleTodayClick, }, { label: 'Accept', onClick: handleAcceptClick, }, ], sx: { padding: 0 }, }, textField: () => ({ size: 'small', InputProps: { placeholder: value ? '' : 'Forever', sx: { height: '40px' }, slotProps: { input: { sx: { height: '21px !important', fontSize: '14px !important', padding: '8.5px 30px !important', }, }, }, }, }), }} /> </Stack> ) } export default ResponsiveDateTimePicker
关键修改点说明:
- 新增内部临时状态
tempValue:用户选择日期、小时、分钟时,只会更新这个临时状态,不会直接触发父组件的onAccept。 - 关闭自动确认:设置
onAccept={() => {}},覆盖默认的自动触发逻辑。 - 禁止选择后自动关闭:添加
closeOnSelect={false},用户选完分钟后弹窗不会关闭,可返回修改日期、小时。 - 自定义ActionBar按钮:替换默认的
actions数组,为Today和Accept按钮绑定自定义点击事件,只有点击Accept时才调用父组件的onAccept。
这样就能实现:用户可以自由修改日期、时间的各个部分,直到主动点击Accept按钮才确认选择,完全符合需求。
内容的提问来源于stack exchange,提问作者Shalvin
相关产品推荐
相关产品推荐

