javascript - 隐藏的输入不会触发 React 的 onChange 事件
问题描述
我在 React 的输入字段中遇到了一个奇怪的问题。我知道hidden
输入不会触发input
或change
事件的事实。但是,即使我手动触发它们,React 的onChange
事件仍然没有被调用。
我在这里触发了change
和input
事件,因为 ReactonChange
实际上是input
事件。当我在inputRef
( addEventListener("change", () => { ... })
) 上设置一个事件侦听器以进行测试时,它被毫无问题地调用。然而,事实证明 React 在拦截它时遇到了一些问题。
这是我当前的代码:
const [fieldValue, setFieldValue] = useState(0);
const inputRef = useRef<HTMLInputElement>(null);
const handleClick = useCallback((): void => {
if (inputRef.current) {
inputRef.current.dispatchEvent(new Event("change", { bubbles: true }));
inputRef.current.dispatchEvent(new Event("input", { bubbles: true }));
}
setFieldValue(prev => prev + 1);
}, []);
JSX:
<input type="hidden" ref={inputRef} value={fieldValue} onChange={(e) => { console.log("React:onChange"); }} />
<button type="button" onClick={handleClick}>Hit it</button>
我在这里做错什么了吗?我还需要做什么才能正确触发 React 的onChange
事件?
解决方案
React 中的事件由 react-dom 通过不同的插件处理。输入事件由SimpleEventPlugin管理(参见https://github.com/facebook/react/blob/master/packages/react-dom/src/events/SimpleEventPlugin.js)
这个插件获取一个事件并重新调度它而不会干扰太多。因此,您可以将其作为原生事件进行调度,并且无需太多更改即可作为SyntheticEvent触发。
更改事件由ChangeEventPlugin处理(请参阅https://github.com/facebook/react/blob/master/packages/react-dom/src/events/ChangeEventPlugin.js)。这个插件有这个目的:
这个插件创建了一个
onChange
事件来规范跨表单元素的更改事件。此事件在可以更改元素的值而不会看到闪烁的时候触发。
该插件会触发更改事件,但不完全与本机更改事件一样。例如,文本输入元素上的本机更改事件仅在模糊时触发。请参阅https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event
对于某些元素,包括 ,在控件失去焦点之前不会触发 change 事件。
但是对于 React,它的触发方式不同,每次值的变化。为此,它由具有以下限制的插件处理:该事件将仅在以下输入类型上触发:
color: true,
date: true,
datetime: true,
'datetime-local': true,
email: true,
month: true,
number: true,
password: true,
range: true,
search: true,
tel: true,
text: true,
time: true,
url: true,
week: true
所以在隐藏的输入上,react 会停止调度。
另一个限制是只有当输入的值实际发生变化时才会调度事件。看
if (updateValueIfChanged(targetNode)) {
return targetInst;
}
因此,即使在受支持的输入上,您的调度也不会通过插件。您可以在此代码段中看到它,通过操作用于获取输入值的方法,您可以设法调度事件。
class Hello extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
//_valueTracker.getValue is used for comparing the values of the input. If you write fake value in the input it'll dispatch, anything else won't
document.getElementsByTagName('INPUT')[0]._valueTracker.getValue = () => {
return 'fake value'
}
}
render() {
const handleClick = () => {
if (this.myRef) {
this.myRef.current.dispatchEvent(new Event("change", {
bubbles: true
}));
}
};
return <div > < input type = "text"
ref = {
this.myRef
}
onChange = {
(e) => {
console.log("React:onChange");
}
}
/><button type="button" onClick={handleClick}>Hit it</button > < /div>
}
}
ReactDOM.render( <
Hello name = "World" / > ,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container">
</div>
所以对于隐藏的输入,没有办法让它工作(注意是符合标准的)。对于文本(或其他支持的输入),您可以但您需要或多或少地破解比较事件之前的值与事件之后的值的方法。
推荐阅读
- node.js - 从流中读取时的NodeJs可读错误
- firebase - 类型错误:将图像从本机反应上传到firebase时网络请求失败
- java - 为班级编写简单的电子表格处理器。Location 类的方法没有通过单元测试。为什么有任何帮助?
- react-big-calendar - 如何在 react-big-calendar 中禁用一天
- c# - PrimeNg 日历日期无法正常工作
- automation - 运行测试套件时如何处理应用程序“崩溃”。(Android)
- flutter - 如果有足够的空间,则在同一行中放置 2 行
- python - 熊猫合并显示来自单个数据框的列
- api - Sendgrid 在一个请求中创建模板和版本
- python - 从满足条件的 df 中提取任意 2 行 - Pandas