【问题标题】:In React, what's the difference between onChange and onInput?在 React 中,onChange 和 onInput 有什么区别?
【发布时间】:2016-11-10 09:55:01
【问题描述】:

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

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

【问题讨论】:

  • 我编辑了我的帖子以使其更清晰。我说的是 textarea,而不是单选按钮或复选框。
  • 那是完全错误的,React 不仅仅是 JS。在某些情况下,事件的行为略有不同(例如onChange)。不,将文本粘贴到文本区域(在 React 中)会触发 onChangeonInput。随意测试一下,你会看到的。
  • 对于
  • 我认为 onChange 是更安全的选择。我什至尝试以编程方式更改 textarea 的值,我想onChange 可能会触发而onInput 不会触发,但两者都会触发。
  • 是的,现在在查看了一些 React Docs 之后,我看到 React 做了很多类似 jQuery 的事情,它规范了事件,是的。 onChange 似乎是一种首选方式。是的。 React 无非就是 JS。没有什么特别的魔法。只是规则。

标签: javascript reactjs dom-events


【解决方案1】:

一个区别似乎是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

【讨论】:

    【解决方案2】:

    好像没什么区别

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

    React docs - Forms

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

    Document how React's onChange relates to onInput #3964

    来自 cmets 关于该问题的引述:

    我不明白为什么 React 选择让 onChange 表现得像 onInput 那样。据我所知,我们无法恢复旧的 onChange 行为。文档声称这是一个“用词不当”,但实际上并非如此,它会在发生更改时触发,直到输入也失去焦点。

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

    这没什么大不了的,但在我看来,React 抛弃了一个有用的事件并偏离了标准行为,而实际上已经有一个事件这样做了。

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

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

    尽管 React 是建立在 JS 之上的,并且已经看到了巨大的采用率,但 React 的存在是为了将大量功能隐藏在它自己的(相当小的)API 下。曾经很明显的领域是事件系统,其中有很多在表面下发生的事情,实际上与标准 DOM 事件系统完全不同。不仅在于哪些事件做什么,还在于何时允许数据在事件处理的哪个阶段持久存在。您可以在此处阅读更多相关信息:

    React Event System

    【讨论】:

    • 最后一段具有误导性/不真实。
    • @rounce 这是一种笼统的陈述......哪一部分有误导性? JSX is 只是糖衣 JS(这是 cmets 对另一个答案的声明),因为它直接转换为 JS(您甚至可以手动编写该 JS)。 React 本身就是一个框架,它做的不仅仅是直接映射到 DOM...请详细说明。
    • React 不是一个框架(它在哪里提供路由、持久性、网络 I/O 管理等?),它是一个 ,它提供了用于操作的核心抽象通过特定于平台的后端(react-dom、react-native 等)显示树。
    • 哇好。我有点同意它更像是一个库而不是一个框架,但是因为那个而称该段落具有误导性/不真实?我也不同意框架应该提供 Web 应用程序的所有方面的概念......例如,有路由框架,或者像 redux 这样的状态管理框架。在我看来,一个框架可以让你填充一台正常运行的机器的各个部分。在 Redux 的情况下,您填写 reducers。在 Express 的情况下,您填写请求处理程序和中间件。等等。但至少可以说是一个灰色地带。
    • 完全同意。争论库和框架之间的区别真的是浪费时间。只是取决于你工作的抽象级别。
    【解决方案3】:

    没有区别

    React 没有默认 'onChange' 事件的行为。我们在 react 中看到的 'onChange' 具有默认的 'onInput' 事件的行为。因此,要回答您的问题,两者的反应没有区别。我在 GitHub 上提出了同样的问题,这就是他们要说的:

    我认为在做出这个决定的时候(大约 4 年前?),onInput 在浏览器之间的工作并不一致,并且让从其他平台访问网络的人感到困惑,因为他们期望“改变” 每次更改都会触发事件。在 React 的情况下,这是一个更大的问题,因为如果您未能及时处理更改,受控输入将永远不会更新,导致人们认为 React 已损坏。所以团队将其命名为 onChange。

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

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

    本文还将提供更多见解。作为缺少默认“onChange”的解决方法,文章建议收听“onBlur”事件。

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

    【讨论】:

    • 我似乎偶然发现了不同之处。 React 的 onChange 在选择和替换一个字符时不会触发,onInput 会触发。
    【解决方案4】:

    对于偶然发现此问题并寻找一种方法来侦听基于 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 的复选框时摆脱这种反转,但这会破坏代表的几个复选框页面不同位置的相同状态保持同步。 (在这两种情况下,我都没有将 onInput 处理程序传递给 CustomInput 复选框。)

    【讨论】:

    • 真正的救星,谢谢。似乎 React 社区/开发人员陷入了这个问题,但他们可以就如何解决它达成一致。向后兼容性是如此可悲的事情,即使是明显的错误也只是因为很少有人将错误用作功能而被保留......我对&lt;input type="date/time"&gt; 有问题,而onChange 甚至因为UI导航用户需要选择日期而被触发/时间。在普通的 JS 中,onchange 仅在用户关闭 UI 时触发一次 - 所以当他最终选择日期时。你的这个类使它再次工作:)
    【解决方案5】:

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

    如果您不想在用户完成编辑之前对其进行处理,请使用 onBlur。 :)

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-27
        • 2016-03-29
        相关资源
        最近更新 更多