在 React 中,onChange 和 onInput 的区别是什么?

我试图寻找这个问题的答案,但是大多数问题都在 React 的上下文之外,在 React 中,onChange触发模糊。

在执行各种测试时,我似乎无法说出这两个事件之间的区别(当应用到文本区时)。有人能解释一下吗?

101387 次浏览

似乎没有真正的区别

由于某种原因,React 将 Component.onChange的侦听器附加到 DOMelement.oninput事件。请参阅表格上的文件说明:

反应文件-表格

有更多的人对这种行为感到惊讶。要了解更多细节,请参考 React 问题跟踪器上的这个问题:

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

引述关于这一问题的评论意见:

我不明白为什么 React 选择让 onChange 像 onInput 那样运行。据我所知,我们没有办法让老的变化行为回来。文档声称这是一个“用词不当”,但事实并非如此,当有变化时,它确实会触发,只是在输入也失去焦点之前不会触发。

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

这没什么大不了的,但在我看来,“反应”抛弃了一个有用的事件,偏离了标准行为,而这个事件已经做到了这一点。

我100% 同意这个注释... ... 但是我想现在改变它带来的问题比它解决的问题要多,因为已经写了太多依赖于这种行为的代码。

React 不是官方 WebAPI 集合的一部分

即使 React 是建立在 JS 之上的,并且已经看到了巨大的采用率,作为一种技术,React 存在于它自己的(相当小的) API 之下,以隐藏大量的功能。这一点在事件系统中非常明显,在事件系统的表面下有很多事情发生,实际上与标准的 DOM 事件系统截然不同。不仅要考虑哪些事件执行哪些操作,还要考虑在事件处理的哪个阶段允许数据持久存储的时间。你可以在这里了解更多:

反应事件系统

没有区别

React 没有默认的“ onChange”事件的行为。我们在响应中看到的‘ onChange’具有默认的‘ onInput’事件的行为。所以为了回答你的问题,他们的反应没有什么不同。我在 GitHub 上提出了同样的问题,他们是这样说的:

我认为在做出这个决定的时候(大约4年前?)OnInput 不能在不同的浏览器之间一致地工作,而且会让从其他平台访问网络的人感到困惑,因为他们会期望“变更”事件在每次变更时都会触发。对于 React 来说,这是一个更大的问题,因为如果你不能及时处理变化,受控的输入永远不会更新,导致人们认为 React 是坏的。所以球队决定改变。

回想起来,填充 onInput 并保留其名称可能是一个更好的主意,而不是更改其他事件的行为。但那已经是很久以前的事了。将来我们可能会重新考虑这个决定,但是我只是鼓励您将其视为 React DOM 的一个特例(您很快就会习惯它)。

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

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

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

最近我得到了一个错误,onChange不允许复制和粘贴在 IE11的输入字段。而 onInput事件允许这种行为。我在文档中找不到任何可以描述这一点的文档,但它确实显示了两者之间的区别(预期的或不预期的)。

正如您在这里的各种评论中所看到的,React 对 onChange 和 onInput 的评价是一样的,而不是对这个决定的优点进行辩论。这就是解决办法。

当您不想处理用户的编辑直到它们完成时,可以使用 onBlur。 :)

对于那些无意中发现这个问题并寻找一种方法来监听实际的、基于 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事件也是在用户按回车键时触发的,只有当值实际发生变化时才会触发。

我还在积累这个 CustomInput组件的经验。例如,复选框的行为很奇怪。我要么在 onChange处理程序中反转 event.target.checked,同时用 checked将值传递给复选框,要么在用 defaultChecked将值传递给复选框时去除这种反转,但这会打破在页面不同位置表示相同状态的几个复选框保持同步。(在这两种情况下,我都没有为复选框向 CustomInput传递 onInput处理程序。)

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

看这个沙盒: https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js

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

区别在于 oninput 事件在元素的值更改后立即发生,而 onchange 在元素失去焦点时发生,在内容更改后发生。