react: [RFC] onChange -> onInput, and don't polyfill onInput for uncontrolled components
onChange is a nicer name for what onInput does and the fact that it has propagated up to other high-level components as the default name is much nicer than onInput as a high level event name.
Generally it has been helpful for the many new-comers to React that don’t know the DOM well (which is a lot more than the inverse). However, that doesn’t change the fact that it can be confusing for people that are familiar.
Unfortunately, changing it now would cause confusion for everyone that already knows React.
The reason I’d like to change it now is because I’d like to get away from polyfilling it for uncontrolled components. This use case is filled with all kinds of imperative code which leads to edge cases. E.g. reading/setting e.target.value or reading/setting ref.value.
When you use controlled components you shouldn’t need to touch them imperatively and therefore won’t hit the edge cases. Ideally we should get away from reading from e.target.value and instead just pass the value directly to the event handler.
Proposal:
Controlled Components
onInput: Polyfilled and works likeonChangedoes today. It is allowed to over-fire many events even if nothing changed. May have special Fiber rules regarding synchronous flushing. Optional: Passvalueas second arg.onChange: Works likeonInputfor one version but warns about being deprecated and suggests switching toonInput. In next version it works like the browser but still warns and tells you to useonInputforever.
Optional: Add a getter/setter on DOM .value in development mode and warn if this is used directly.
Uncontrolled Components
onInput: Not polyfilled. Works however the browser works. Warns about browser differences if you don’t also specifyonClick,onKeyDownand/oronKeyUp. The warnings suggests implementing those listeners to cover more edge cases, or switch to a controlled component.onChange: Not polyfilled. Works however the browser works.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 39
- Comments: 19 (9 by maintainers)
I really the general concept of this change. It allows simplifying a really complicated polyfill while also actively encouraging folks to use the better controlled input pattern. I’d really encourage ya’ll to please give a full major version for this to warn, and not add it in v15.6. The entire “form” library ecosystem in React is built on top of the behavior of onChange, and custom inputs most copy the onChange/value pattern.
Another reason is access to
input.validitywhich is needed for input validation.@sebmarkbage
IMO losing access to
e.targetwould be a regression - I’d like to keep having access to the element and it’s props, which can be useful (access selection range,data-*props etc)Bump
Wondering if you guys going to proceed in this
onChange/onInputmatter ?I think in the long-term we probably want to move away from adding more event namespaces to ReactDOM, including the changing of
onChangeandonInput. A better approach would be to move this custom ReactDOM logic to a separate element/node. Doing so would allow us to move forward with higher-level abstractions without them conflicting with the existing and future DOM namespaces on the web platform.Any update on this issue?
It seems to me that, instead of waiting for this issue to be resolved, you can simply write a custom input component, which exposes the DOM-based
changeevent. This is how I implemented it (with TypeScript):Please let me know if you see ways to improve this approach or encounter problems with it. I’m still gaining experience with this
CustomInputcomponent. For example, checkboxes behave strangely. I either have to invertevent.target.checkedin theonChangehandler while passing the value to the checkbox withcheckedor can get rid of this inversion when passing the value to the checkbox withdefaultCheckedbut this then breaks that several checkboxes representing the same state in different places on the page keep in sync with the state. (In both cases, I didn’t pass anonInputhandler to theCustomInputfor checkboxes.)@sebmarkbage I’ve previously brought up separating uncontrolled and controlled inputs entirely and you guys seemed to generally agree, might this be a good time for that too or is that no longer relevant? I.e.
<input>is uncontrolled and<FooBarInput>is a React-enhanced implementation with controlled behavior. Could possibly even be its own package? IMHO if we’re going with removing attribute whitelists then not special-casing native inputs seems like a step in the same direction.Regarding
onChangevsonInput. Unless there are IME-issues with hidingonInputthen that seems fine. ButonChangeseems like a generally good React naming convention for components that change, also, checkboxes/radios etc would still report their value change viaonChangeand notonInputright?