我正在创建具有一些额外功能的自定义 React 组件。我想让它尽可能接近默认的浏览器行为。每当我更改表单输入中的某些内容时,我希望更改事件冒泡到表单。不幸的是,我无法让它发挥作用。
我读到,即使在 React 的合成事件系统中,“change”事件显然也有些特殊。所提出的解决方案都不适合我,因为它们适用于较旧的 React 版本。
为了简化我的问题,我创建了这个演示,我想做的是从输入的 onPointerDown 或任何其他事件处理程序中触发 form.onChange 。当然,我不能直接调用 form.onChange,因为我无法控制这部分代码。一切都应该通过事件冒泡来完成。在 React 中是否有可能?我已经在一些流行的 UI 库中对其进行了测试,到目前为止,它们都没有对非本机选择组件执行此操作。
export function Demo() {
return (
<form
onChange={(event) => {
const form = event.currentTarget;
const formData = new FormData(form);
console.log(JSON.stringify(Array.from(formData)));
}}
>
<input
name="name"
onPointerDown={(event) => {
const changeEvent = new Event("change", { bubbles: true });
event.currentTarget.dispatchEvent(changeEvent);
}}
/>
</form>
);
}
您不能通过从输入分派来直接调用表单的 onChange 事件。
表单的 onChange 事件将在任何表单的输入更改时触发。
React 通过跟踪表单元素的值变化来优化事件处理。如果没有实际更改输入的值,React 可能不会将该事件识别为有意义的更改,即使该事件已调度。
我认为这是合理的,因为如果输入的值没有改变,那么在表单上调用 onChange (在你的例子中从输入的 onPointerDown )有什么意义?
解决方案1:根据需要添加事件到表单。
以下代码显示相同。
编码亮点:
a. ref 对象用于访问表单对象。
b.处理程序 addEventToForm 将向表单对象添加事件。
c.处理程序 listenerForAllFormEvents 是同一个处理程序,将侦听所有添加的事件。
App.js
import { useRef } from 'react';
export default function Demo() {
const refForm = useRef();
function listenerForAllFormEvents(event) {
const form = event.currentTarget;
const formData = new FormData(form);
console.log(JSON.stringify(Array.from(formData)));
}
function addEventToForm(event) {
const eventName = event._reactName.substr(2).toLowerCase();
refForm.current.addEventListener(eventName, listenerForAllFormEvents);
}
return (
<form ref={refForm}>
<input
name="name"
onPointerDown={addEventToForm}
onChange={addEventToForm}
/>
</form>
);
}
试运行
// Events vs. Console log generated:
// ------------------------------------------------------------
// On pointing mouse on the input field [["name",""]]
// On pressing tab from the field
// after typing the text 'good name' [["name","good name"]]
解决方案 2:在表单对象中使用“捕获子事件”处理程序
请参阅下面的示例代码。
表单对象中的以下处理程序 formEventCapture 将捕获其子组件中所有类型的事件 - 单击和更改。
应用程序.js
export default function Demo() {
function formEventCapture(event) {
const form = event.currentTarget;
const formData = new FormData(form);
console.log(JSON.stringify(Array.from(formData)));
}
return (
<form onClickCapture={formEventCapture} onChangeCapture={formEventCapture}>
<input name="name" />
</form>
);
}
试运行
// Events vs. Console log generated:
// ------------------------------------------------------------
// On pointing mouse on the input field [["name",""]]
// On typing the text 'good name'
// [["name","g"]]
// [["name","go"]]
// [["name","goo"]]
// [["name","good"]]
// [["name","good "]]
// [["name","good n"]]
// [["name","good na"]]
// [["name","good nam"]]
// [["name","good name"]]