【问题标题】:Cannot reset MUI DatePicker from keydown event无法从 keydown 事件重置 MUI DatePicker
【发布时间】:2022-01-14 13:41:00
【问题描述】:

我遇到了这种我无法解释的奇怪行为。代码的沙箱可以在here找到。

我正在尝试通过按 DELBACKSPACE 添加重置 readOnly 字段的可能性,但它不起作用。在尝试重现该问题时,我可以在按下按钮时重置它,但在键盘上打字时则不行;为什么?

import React, { useCallback, useState } from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import AdapterDayjs from "@mui/lab/AdapterDayjs";
import LocalizationProvider from "@mui/lab/LocalizationProvider";
import DatePicker from "@mui/lab/DatePicker";
import Typography from "@mui/material/Typography";

import frLocaleDate from "dayjs/locale/fr";

export default function BasicDatePicker() {
  const [value, setValue] = useState(null);
  const [message, setMessage] = useState("");

  const handleChanged = useCallback((newValue) => {
    setMessage("Value changed to " + newValue);
    setValue(newValue);
  }, []);
  const handleInputKeyDown = useCallback((event) => {
    if (event.keyCode === 8 || event.keyCode === 46) {
      setMessage("Reset through handleInputKeyDown");
      setValue(null);
    }
  }, []);
  const handleReset = useCallback(() => {
    setMessage("Reset through handleReset");
    setValue(null);
  }, []);

  return (
    <LocalizationProvider dateAdapter={AdapterDayjs} locale={frLocaleDate}>
      <Typography>Try pressing DEL or BACKSPACE to clear</Typography>
      <DatePicker
        clearable
        showTodayButton
        label="Basic example"
        inputFormat="LL"
        value={value}
        onChange={handleChanged}
        renderInput={({ InputProps, inputProps, ...props }) => (
          <TextField
            fullWidth
            margin="dense"
            size="small"
            onKeyDown={handleInputKeyDown}
            InputProps={{ ...InputProps }}
            inputProps={{ ...inputProps, readOnly: true, placeholder: "" }}
            {...props}
          />
        )}
      />
      <Button onClick={handleReset}>Reset</Button>
      <Typography>
        Debug: <pre>{message}</pre>
      </Typography>
      <Typography>
        Current value: <pre>{JSON.stringify(value)}</pre>
      </Typography>
    </LocalizationProvider>
  );
}

我尝试在handleInputKeyDown函数内部延迟setValue(null),但是即使值为null,输入仍然显示一个值。

** 更新**

仅当字段具有焦点时才会出现此问题。如果我像这样更改handleInputKeyDown,请按 DEL 并单击远离输入字段(即使其失去焦点),然后该字段在 2 秒后重置(当 setTimeout 调用处理函数)。

const handleInputKeyDown = useCallback((event) => {
  if (event.keyCode === 8 || event.keyCode === 46) {
    setTimeout(() => {
      setMessage("Reset through handleInputKeyDown");
      setValue(null);
    }, 2000);
  }
}, []);

我尝试给DatePicker组件添加一个引用,然后调用ref.current.blur();,但是不起作用,并且元素没有失去焦点。

** 更新 2 **

按照 Emanuele Scarabattoli 的回答和解释,这似乎也适用于我的特殊情况:

const handleInputKeyDown = useCallback((event) => {
  //event.preventDefault();
  if (event.keyCode === 8 || event.keyCode === 46) {
    setTimeout(() => {
      event.target.blur();  // blur outside the scope of keyDown
      setMessage("Reset through handleInputKeyDown");
      setValue(null);
    }, 0);
  }
}, []);

这引发了另一个问题:当字段获得焦点时,更改值不会更新显示。当用户选择字段时,这是有问题的,但程序以编程方式更新它;值得到更新,但用户没有更改的反馈。

【问题讨论】:

  • 我之前提供了一个错误的答案(然后被删除),现在我完全改变了它,它正在工作(至少通过改变你提供的 sn-p 中的代码)。
  • 关于上次更新,我的建议是有条件地使用blurpreventDefault,具体取决于keyCode。让我知道这是否可行,以便我更新答案。
  • 似乎这两种解决方案(使用event.preventDefault() 和延迟event.target.blur())似乎都适用于 DELBACKSPACE 所以没关系暂且。这两个问题都已在 Github 上发布(未提供,因此我没有交叉发布)

标签: javascript reactjs material-ui


【解决方案1】:

根据您在更新中的建议,我得到了这个解决方法:

const handleInputKeyDown = useCallback((event) => {
  event.target.blur() // As you suggested
  event.preventDefault() // This does the trick
  if (event.keyCode === 8 || event.keyCode === 46) {
    setMessage("Reset through handleInputKeyDown");
    setValue(null);
  }
}, [setMessage, setValue]); // Better to add, as per React documentation

可能的解释

免责声明:此解释未经论证,不一定正确!

由于DEL 键作为默认行为被用作删除字符的键,我的印象是必须阻止默认行为以使其以不同的方式工作。这可能是由于event 中与event.target.value 相关的原因。我的意思是,浏览器可能会在按下DELESC 的情况下传播一个事件,该事件最终会执行类似于valueOfTheInput = event.target.value 的操作,即使value 本身没有改变,所以我们需要避免这种情况。

【讨论】:

  • 太棒了!现在我很想知道发生了什么以及为什么需要event.preventDefault()! :D
  • @YanickRochon,你不知道花了多少时间哈哈哈好吧,因为DEL 是作为删除字符的键(像往常一样),我的印象是默认行为有被阻止使其以不同的方式工作。可能是由于事件中与event.target.value 相关的事情。让我在答案中添加这个解释。这东西要我死了,我必须找到答案XD
  • 我在我的问题中添加了 Update 2。不需要回答,但该组件对我来说仍然是一个严重的问题。
  • 查看对问题的评论 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多