我在 React 的输入字段中遇到了一个奇怪的问题。我知道 hidden
输入不会触发 input
或 change
事件。然而,即使我手动触发它们,React 的 onChange
事件仍然没有被调用。
我在这里触发了 change
和 input
事件,因为 React 的 onChange
实际上是 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 )
这个插件获取一个事件并重新发送它而不会造成太多干扰。因此,您可以将其作为原生事件进行分派(dispatch),并且无需太多更改即可作为 SyntheticEvent 触发。
Change 事件由 ChangeEventPlugin 处理(参见 https://github.com/facebook/react/blob/master/packages/react-dom/src/events/ChangeEventPlugin.js )。这个插件有这个目的:
This plugin creates an
onChange
event that normalizes change events across form elements. This event fires at a time when it's possible to change the element's value without seeing a flicker.
插件会触发更改事件,但与 native 更改事件不完全相同。例如,文本输入元素上的 native 更改事件仅在模糊时触发。参见 https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event
For some elements, including , the change event doesn't fire until the control loses focus.
但是在 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;
}
因此,即使在受支持的输入上,您的调度也不会通过插件。您可以在此代码段中看到它,通过操作用于获取输入值的方法,您可以设法分派(dispatch)事件。
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>
所以对于一个hidden input,是没办法让它起作用的(注意是符合标准的)。对于文本(或其他支持的输入),您可以,但您或多或少需要破解比较事件之前的值和事件之后的值的方法。
关于javascript - 隐藏输入不会触发 React 的 onChange 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57943234/