admin管理员组文章数量:1332638
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 | Show 1 more comment8 Answers
Reset to default 185It 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 2onInput
. - Now select all and type "B" again, this till trigger a new
onInput
event, but noonChange
.
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:
- Click inside the input field and type
a
to insert a new value (value change). This emits thenative onInput
,React onInput
, andReact onChange
log records. - Click outside the input field to commit the value change. This emits the
native onChange
log record. - Highlight the value in the input field and type
a
again to replace it with the same value (no value change). This emits thenative onInput
andReact onInput
log records. - 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
版权声明:本文标题:javascript - In React, what's the difference between onChange and onInput? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736772424a1952154.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
onChange
). And no, pasting text in a textarea (in React) triggers bothonChange
andonInput
. Feel free to test in a fiddle and you'll see. – ffxsam Commented Jul 7, 2016 at 22:54onChange
would trigger andonInput
would not, but both trigger. – ffxsam Commented Jul 7, 2016 at 23:02