在 React 中,onChange 和 onInput 有什么区别

In React, what's the difference between onChange and onInput?

本文关键字:onInput 什么 区别 onChange React      更新时间:2023-09-26

我尝试过四处寻找答案,但其中大多数都在 React 的上下文之外,onChange模糊时触发。

在执行各种测试时,我似乎无法说出这两个事件有何不同(当应用于文本区域时)。谁能对此有所了解?

似乎没有真正的区别

出于某种原因,React 将Component.onChange的侦听器附加到 DOM element.oninput事件。请参阅文档中有关表单的说明:

反应文档 - 表单

有更多的人对这种行为感到惊讶。有关更多详细信息,请参阅 React 问题跟踪器上的此问题:

记录 React 的 onChange 与 onInput #3964 的关系

引述关于该问题的评论:

我不明白为什么 React 选择让 onChange 的行为像 onInput 一样。据我所知,我们无法恢复旧的onChange行为。文档声称这是一个"用词不当",但事实并非如此,当有变化时,它确实会触发,只是直到输入也失去焦点。

对于验证,有时我们不想在它们完成键入之前显示验证错误。或者,也许我们只是不希望每次击键都重新渲染。现在唯一的方法是使用 onBlur,但现在我们还需要检查值是否已手动更改。

这没什么大不了的,但在我看来,当已经有一个事件这样做时,React 扔掉了一个有用的事件并偏离了标准行为。

我 100% 同意评论...但我想现在改变它会带来比它解决的问题更多的问题,因为已经编写了如此多依赖于这种行为的代码。

React 不是官方 Web API 集合的一部分

尽管 React 建立在 JS 之上,并且采用了率很高,但作为一种技术,React 的存在是为了在自己的(相当小的)API 下隐藏大量功能。一旦在事件系统中,这一点很明显,在表面之下有很多事情发生,实际上与标准的 DOM 事件系统完全不同。不仅在哪些事件执行什么操作方面,而且在何时允许数据保留在事件处理的哪个阶段方面。您可以在此处阅读更多相关信息:

反应事件系统

没有区别

React 没有默认的"onChange"事件的行为。我们在 react 中看到的 'onChange' 具有默认的 'onInput' 事件的行为。所以要回答你的问题,他们俩的反应没有区别。我在 GitHub 上提出了一个关于同样的问题,这就是他们对此的看法:

我认为在做出这个决定时(~4年前?),onInput在浏览器之间不能一致地工作,并且让从其他平台访问网络的人感到困惑,因为他们希望"更改"事件在每次更改时都会触发。在 React 的情况下,这是一个更大的问题,因为如果你不能足够快地处理更改,受控输入永远不会更新,导致人们认为 React 坏了。因此,团队将其称为onChange。

回想起来,最好对 Input 进行填充并保留其名称,而不是更改另一个事件的行为。但那艘船很久以前就航行了。我们将来可能会重新审视这个决定,但我只是鼓励你把它当作 React DOM 的一个怪癖(你很快就会习惯)。

https://github.com/facebook/react/issues/9567

此外,本文将提供更多见解。作为缺少默认"onChange"的解决方法,本文建议侦听"onBlur"事件。

https://www.peterbe.com/plog/onchange-in-reactjs

一个区别似乎是,在选择和替换具有相同字符的字符时,不会触发onChange,而onInput是。

请参阅此沙盒:https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js

  • 在字段中键入"A",然后选择全部并键入"B"。这将触发 4 个事件,2 个onChange和 2 个onInput
  • 现在全选并再次键入"B",直到触发一个新的onInput事件,但没有onChange

对于任何偶然发现这个问题寻找一种方法来监听实际的、基于 DOM 的change事件的人来说,这就是我的做法(用 TypeScript 编写):

import { Component, createElement, InputHTMLAttributes } from 'react';
export interface CustomInputProps {
    onChange?: (event: Event) => void;
    onInput?: (event: Event) => void;
}
/**
 * This component restores the 'onChange' and 'onInput' behavior of JavaScript.
 *
 * See:
 * - https://reactjs.org/docs/dom-elements.html#onchange
 * - https://github.com/facebook/react/issues/3964
 * - https://github.com/facebook/react/issues/9657
 * - https://github.com/facebook/react/issues/14857
 */
export class CustomInput extends Component<Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onInput' | 'ref'> & CustomInputProps> {
    private readonly registerCallbacks  = (element: HTMLInputElement | null) => {
        if (element) {
            element.onchange = this.props.onChange ? this.props.onChange : null;
            element.oninput = this.props.onInput ? this.props.onInput : null;
        }
    };
    public render() {
        return <input ref={this.registerCallbacks} {...this.props} onChange={undefined} onInput={undefined} />;
    }
}

如果您看到改进此方法的方法或遇到问题,请告诉我。与blur不同,change 事件也会在用户按 Enter 时触发,并且仅在值实际更改时才触发。

我仍在获得这个CustomInput组件的经验。例如,复选框的行为很奇怪。我要么必须在onChange处理程序中反转event.target.checked,同时使用 checked 将值传递给复选框,或者在将值传递给带有 defaultChecked 复选框时摆脱这种反转,但这会破坏页面上不同位置代表相同状态的几个复选框保持同步。(在这两种情况下,我都没有将onInput处理程序传递给复选框的CustomInput

正如你在这里的各种评论中看到的那样,React 将 onChange 和 onInput 视为相同,而不是争论这个决定的优点。 这是解决方案。

当您不想在用户完成编辑之前处理他们的编辑时,请使用 onBlur。 :)

最近我遇到了一个错误,onChange不允许在IE11的输入字段中复制和粘贴。而onInput事件将允许该行为。我在文档中找不到任何可以描述这一点的文档,但这确实表明两者之间存在差异(预期与否)。