繁体   English   中英

隐藏的输入不会触发React的onChange事件

[英]Hidden input doesn't trigger React's onChange event

我在React中的输入字段面临一个奇怪的问题。 我知道以下事实: hidden输入不会触发input也不会change事件。 但是,即使我手动触发了它们,React的onChange事件仍然没有被调用。

我在这里触发changeinput事件,因为React的onChange实际上是input事件。 当我出于测试目的在inputRefaddEventListener("change", () => { ... }) )上设置事件侦听器时, inputRef它没有任何问题。 但是,事实证明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事件,我onChange要做什么?

用户更改元素值时会触发onChange事件-在您的情况下,您是通过编程方式更改输入值,因此onChange不会触发

值更改时将触发 onInput 事件 -无论如何更改。 因此,您需要添加onInput甚至监听器,而不是onChange

<input type="hidden" ref={inputRef} value={fieldValue} onInput={(e) => { console.log("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> 

因此,对于隐藏的输入,无法使其工作(请注意,它符合标准)。 对于文本(或其他受支持的输入),您可以,但是您需要或多或少地修改将事件之前的值与事件之后的值进行比较的方法。

我认为您可能会以错误的方式进行处理。 当您单击按钮时,您希望状态更新,并且新状态会反映在隐藏字段中。 而不是检查隐藏字段中的更改,您应该检查状态的更改,您可以使用useEffect轻松地进行useEffect 这样,您就可以省去引用,而不会使事情复杂化。

function App() {
  const [fieldValue, setFieldValue] = useState(0);

  function handleClick() {
    setFieldValue(prev => prev + 1);
  }

  useEffect(() => {
     console.log('React:changed');
  }, [fieldValue]);

  return (
    <>
      <input type="hidden" value={fieldValue} />
      <button type="button" onClick={handleClick}>
        Hit it
      </button>
    </>
  );
}

沙盒

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM