为什么 <form> 上的 onChange 事件处理程序从 <select> 中获取分派的事件,而不是 <input>?

Why does the onChange event handler on <form> pick upp dispatched events from <select>, but not <input>?

我正在用 React 构建一个包含许多复杂表单的应用程序,我正在尝试在 <form> 元素上使用 onChange 事件处理程序。

<form onChange={handleChange}>
  <input name="input1" />
  <input name="input2" />
  ...
</form>

这在监听常规 HTML 输入的变化时效果很好,但是在构建 <CustomInput> 时,我无法触发 <form> 上的 onChange。

我创建了一个“隐藏的”<input> 并手动调度了一个 Event("change"),但它没有被 <form> 上的 onChange 拾取,但是,它确实适用于<select> 输入。

import { useRef } from "react";

function App() {
  const inpRef = useRef();
  const selRef = useRef();

  function onChange(e) {
    console.log(e.target.name); // Only "select" is logged
  }

  function dispatchChange() {
    inpRef.current.dispatchEvent(new Event("change", { bubbles: true }));
    selRef.current.dispatchEvent(new Event("change", { bubbles: true }));
  }
  return (
    <>
      <form onChange={onChange}>
        <input ref={inpRef} name="input" />
        <select ref={selRef} name="select" />
      </form>
      <button onClick={dispatchChange}>Trigger change</button>
    </>
  );
}

export default App;

为什么 <select> 的“更改”事件会触发 onChange 而不是 <input>

出现此问题是因为输入的“更改事件”非常特殊。它由“ChangeEventPlugin”管理。

此插件的限制之一是只有在输入值实际发生变化时才会调度“change”事件。

要解决这个问题,您必须在代码中添加:

useEffect(() => {
    inpRef.current._valueTracker.getValue = () => {
      return 'fake value'
    }
  }, []);

当然还要导入“useEffect”。

import { useEffect, useRef } from 'react';

所以,最后,完整的代码将是:

import { useEffect, useRef } from 'react';

function App() {
  const inpRef = useRef();
  const selRef = useRef();

  function onChange(e) {
    console.log(e.target.name); // Only "select" is logged
  }

  function dispatchChange() {
    inpRef.current.dispatchEvent(new Event("change", { bubbles: true }));
    selRef.current.dispatchEvent(new Event("change", { bubbles: true }));
  }

  useEffect(() => {
    inpRef.current._valueTracker.getValue = () => {
      return 'fake value'
    }
  }, []);

  return (
    <>
      <form onChange={onChange}>
        <input ref={inpRef} name="input" />
        <select ref={selRef} name="select" />
      </form>
      <button onClick={dispatchChange}>Trigger change</button>
    </>
  );
}

export default App;

希望对您有所帮助。 祝你有美好的一天,新年快乐!