admin管理员组

文章数量:1331083

I've tried searching around for an answer to this, but most of them are outside the context of React, where onChange triggers upon blur.

In performing various tests, I can't seem to tell how these two events are different (when applied to a textarea). Can anyone shed some light on this?

I've tried searching around for an answer to this, but most of them are outside the context of React, where onChange triggers upon blur.

In performing various tests, I can't seem to tell how these two events are different (when applied to a textarea). Can anyone shed some light on this?

Share Improve this question edited Aug 19, 2019 at 9:47 Brian Tompsett - 汤莱恩 5,87572 gold badges61 silver badges133 bronze badges asked Jul 7, 2016 at 22:35 ffxsamffxsam 27.7k34 gold badges99 silver badges150 bronze badges 6
  • 2 I edited my post to be clearer. I was speaking specifically about textarea, not radio buttons or checkboxes. – ffxsam Commented Jul 7, 2016 at 22:48
  • 2 That's quite false, React is not just JS. And events behave slightly differently in some cases (such as onChange). And no, pasting text in a textarea (in React) triggers both onChange and onInput. Feel free to test in a fiddle and you'll see. – ffxsam Commented Jul 7, 2016 at 22:54
  • For <input> and <textarea>, onChange supersedes — and should generally be used instead of — the DOM's built-in oninput event handler. – Roko C. Buljan Commented Jul 7, 2016 at 23:01
  • I suppose onChange is the safer bet. I even tried to programmatically change the textarea's value, thinking maybe onChange would trigger and onInput would not, but both trigger. – ffxsam Commented Jul 7, 2016 at 23:02
  • 2 Well, I won’t get into splitting hairs.. yes, React is obviously JS, but it changes some of the conventions we’re used to with event handling in HTML. – ffxsam Commented Jul 7, 2016 at 23:09
 |  Show 1 more comment

8 Answers 8

Reset to default 185

It seems there is no real difference

React, for some reason, attaches listeners for Component.onChange to the DOM element.oninput event. See the note in the docs on forms:

React docs - Forms

There are more people that are surprised by this behavior. For more details, refer to this issue on the React issue tracker:

Document how React's onChange relates to onInput #3964

Quote from the comments on that issue:

I don't understand why React chose to make onChange behave like onInput does. As fas as I can tell, we have no way of getting the old onChange behaviour back. Docs claim it's a "misnomer" but not it isn't really, it does fire when there's a change, just not until the input also loses focus.

For validation, sometimes we don't want to show validation errors until they're done typing. Or maybe we just don't want a re-render on every keystroke. Now the only way to do that is with onBlur but now we also need to check that the value has changed manually.

It's not that big of a deal, but it seems to me like React threw away a useful event and deviated from standard behaviour when there was already an event that does this.

I agree 100% with the comment... But I guess changing it now would bring more problems than it solves since so much code had already been written that relies on this behavior.

React is not part of the official Web API collection

Even though React is built on top of JS, and has seen a huge adoption rate, as a technology React exists to hide a whole lot of functionality under its own (fairly small) API. Once area where this is obvious is in the event system, where there's a lot going on under the surface that's actually radically different from the standard DOM event system. Not just in terms of which events do what, but also in terms of when data is allowed to persist at what stage of the event handling. You can read more about that here:

React Event System

There is no difference

React does not have the behaviour of default 'onChange' event. The 'onChange' which we see in react has the behaviour of default 'onInput' event. So to answer your question there is no difference in both of them in react. I have raised an issue on GitHub regarding the same and this is what they have to say about it:

I think that at the time this decision was made (~4 years ago?), onInput didn’t work consistently between browsers, and was confusing to people coming to the web from other platforms, as they would expect the “change” event to fire on every change. In case of React it is a bigger issue because if you fail to handle change soon enough, the controlled inputs never update, leading people to think React is broken. So the team went with calling it onChange.

In retrospect it might have been a better idea to polyfill onInput and keep its name rather than change the behavior of another event. But that ship has sailed a long time ago. We might revisit this decision in the future, but I would just encourage you to treat it as a quirk of React DOM (which you’ll get used to pretty quickly).

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

Also this article will provide more insight. As a workaround for default 'onChange' being missing, the article suggests listening to the 'onBlur' event.

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

One difference seems to be that onChange is not fired when selecting and replacing a character with the same character, while onInput is.

See this sandbox: https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js

  • Type "A" in the field, then select all and type "B". This will trigger 4 events, 2 onChange and 2 onInput.
  • Now select all and type "B" again, this till trigger a new onInput event, but no onChange.

For anyone who stumbled over this issue looking for a way to listen for the actual, DOM-based change event, this is how I did it (written in 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} />;
    }
}

Please let me know if you see ways to improve this approach or encounter problems with it. Unlike blur, the change event is also triggered when the user presses enter and is only triggered if the value actually changed.

I'm still gaining experience with this CustomInput component. For example, checkboxes behave strangely. I either have to invert event.target.checked in the onChange handler while passing the value to the checkbox with checked or get rid of this inversion when passing the value to the checkbox with defaultChecked but this then breaks that several checkboxes representing the same state in different places on the page keep in sync. (In both cases, I didn't pass an onInput handler to the CustomInput for checkboxes.)

As you can see in various comments here, React treats onChange and onInput the same and so, rather than debate the merits of this decision. Here's the solution.

Use onBlur when you don't want to process the user's edits until they're done. :)

Recently I got a bug where onChange would not allow copy and paste in the input field on IE11. Whereas the onInput event would allow that behavior. I could not find any documentation that would describe this in the docs, but that does show there is a difference between the two (expected or not).

Key differences between the onchange and oninput event handlers:

  • both the native and React oninput event handlers fire on value input;
  • the native onchange event handler fires on committed value change;
  • the React onchange event handler fires on value change.

You can observe the following behaviors by running the following program and examining the log records:

  1. Click inside the input field and type a to insert a new value (value change). This emits the native onInput, React onInput, and React onChange log records.
  2. Click outside the input field to commit the value change. This emits the native onChange log record.
  3. Highlight the value in the input field and type a again to replace it with the same value (no value change). This emits the native onInput and React onInput log records.
  4. Click outside the input field to commit the same value. This does not emit any log records.
import { useEffect, useRef, useState } from 'react';

export function App() {
  const ref = useRef(null);
  const [value, setValue] = useState('');
  useEffect(() => {
    const handleChangeNative = () => console.log('native onChange');
    const handleInputNative = () => console.log('native onInput');
    addEventListener('change', handleChangeNative);
    addEventListener('input', handleInputNative);
    return () => {
      removeEventListener('input', handleInputNative);
      removeEventListener('change', handleChangeNative);
    };
  }, []);
  const handleChangeReact = (event) => {
    console.log('React onChange');
    setValue(event.currentTarget.value);
  };
  const handleInputReact = () => console.log('React onInput');
  return (
    <input
      ref={ref}
      value={value}
      onChange={handleChangeReact}
      onInput={handleInputReact}
    />
  );
}

Try it on StackBlitz.

Thank you @Kasper Etter, expanding on your solution, for people using functions instead of classes (here I use an mui component, but you can use also input), this seems to be working:

import { TextField } from "@mui/material";

export default function MyCustomInput() {
    const registerCallbacks  = (element: HTMLInputElement | null) => {
        if (element) {
            element.onchange = (e) => console.log("onChange", (e.target as HTMLInputElement).value);
            element.oninput = (e) => console.log("onInput");
        }
    };

    return (
        <TextField label="Outlined" variant="outlined" inputProps={{ref:registerCallbacks, onChange: undefined, onInput: undefined}} />
    );
}

本文标签: javascriptIn Reactwhat39s the difference between onChange and onInputStack Overflow