React and Preact event handlers aren't the same
Check this out for more info https://github.com/k1r0s/preact-bind-group/issues/2#issuecomment-367981906
Hum, I see.
How would I make the onChange trigger when typing or is there an alternative method?
Found it!
In Preact it's onInput instead of onChange
@esperancaJS Awesome that you found a solution 馃帀 The event system is one of the main differences between react and preact. Preact directly uses native browser events whereas React has its own abstraction built on top of native events. Because of that there may be subtle differences like you discovered.
@developit This tripped me too - onChange did not trigger until the element lost focus (ran into that in #1169 as well after applying the patch from #1168). Input handling differences should really be documented in Differences to React.
@dandv On that page is a section about the synthetic event system of react and the differences to react. If you feel like this isn't enough we are happy to take suggestions (or PRs)
The event system is one of the main differences between react and preact. Preact directly uses native browser events whereas React has its own abstraction built on top of native events. Because of that there may be subtle differences like you discovered.
I was bitten by that this week.
We had added a keyboard shortcut CTRL+S to save changes and close a dialog.
The user immediately reported a bug, where the last thing they had typed into an input with an onChange handler on it, did not get saved. (And, of course, there was a longer process of actually isolating the problem, which was first thought to be that saving after a particular action caused the problem, then that the action behind CTRL+S was somehow different from that of the button, and so on.)
Now, I'd never think to ask for a full event abstraction - but this subtle incompatibility with React is rather problematic, given (in no particular order) that:
onChange rather than onInput.onChange as directed by official documentation, creating subtle compatibility issues with the ecosystem at large.While such a small difference may not seem like a big deal, especially the problem with third-party components could be very significant, both to vendors and consumers, as the resulting subtle issues can be very difficult and time-consuming to isolate.
Having what I feel is a pretty solid understanding of the difference between onChange and onInput, it's actually difficult for me to envision a real-world scenario in which onChange behavior is preferable to onInput, and so my first inclination would be to simply replace change with input when registering event-handlers on HTML elements.
There is at least one obvious drawback to me though, which is I like the fact that Preact event-handlers map directly to DOM event-handlers in a predictable way. I'm not a fan of the "handholding" that seems to be going on in React, if that's what this is - but I'm especially not a fan of creating inconsistencies.
Being compatible with the React ecosystem is a practical concern though, if we want Preact users to have access to component libraries that were designed for React. 馃槓
Probably the "least damage" we could do, is make it work more like React, at least for <input>, <textarea> and <select>, by simply mapping onChange to onInput?
There's a real risk of creating an incompatibility with existing code written specifically for Preact though.
Plus I'm concerned about hiding onChange entirely for that odd, marginal use-case I haven't thought of.
If there's a time to address this though, it's probably before the final release of Preact 10 though?
@marvinhagemeister thoughts?
(and apologies for the long write-up, but this cost myself and others a lot of hours this week - I have concerns about using a third-party component library in a product that will have a lot of keyboard shortcuts like the case described above, and I'd really just like to make sure we consider all the angles.)
@mindplay-dk Thanks for sharing your thoughts on this :+1: The web platform has is really weird when it comes to input vs change.
The good news is that we already map onChange to input in preact/compat. So third-party components that were originally written for react won't run into this issue.
That said I've been wondering if we should move it into core myself. Less and less devs know about input event and it's from my experience a frequent issue newcomers run into. It would cost quite a few bytes for sure, but the DX improvements might be well worth it.
What do you think @andrewiggins , @developit, @lukeed ? Do you know of use cases where change is the preferred event?
The interesting thing is that vue doesn't seem to normalize it, too. The docs refer to the differences in the first section: https://vuejs.org/v2/guide/forms.html
I often use onchange over oninput for the built-in debouncing effect. It's also, natively, supported on more input types.
That said, I would be for aliasing onchange=oninput in preact/compat _only_ since that's what React has done. Let's the developer be correct/expose true DOM behavior, until they're explicitly asking to behave like React.
For the record (I don't see it here): Jason polled this question on Twitter
Oh right, I totally forgot about that twitter thread :+1:
FYI: Doing the aliasing only in preact/compat is the way we do it right now.
I've always thought of Preact as supporting a subset of React - with preact/compat being the package you need if you want full compatibility with React.
So you're saying that's wrong?
I should expect Preact itself to deviate from React's behavior? And preact/compat not only adds more React features, but also "corrects" some of it's behavior?
I'm not trying to be poignant here - just that I've been teaching everyone not to add preact/compat unless there's a React feature they need that isn't supported out of the box.
If that's wrong, may I ask, are there other ways in which Preact is incompatible with React?
If Preact is going to deviate from React in terms of behavior, it would seem reasonable to have these incompatibilities listed front and center somewhere - I think almost everyone I know perceives Preact as supporting a subset of the React API, so that seems like a pretty serious pitfall and a perception that should be corrected.
Although, personally, I would definitely find it much less confusing and far preferable if Preact was fully compatible with React for the subset of the React API that it supports without preact/compat - since, unless I'm using a third-party component, I've really never found anything in the preact/compat package that I need; and even less so with Preact X; and I'd prefer not having to add extra features just to avoid this confusion.
Running into problems because a feature isn't supported is a very different situation from running into subtle variations in behavior that quietly causes things to (even periodically) misbehave.
I mean, just be completely sure that that's what you want, but... is it? really? 馃
I often use
onchangeoveroninputfor the built-in debouncing effect.
@lukeed On which types of input?
According to MDN, the change event behaves identically to blur for <input type=text> and <textarea> elements, so you have an easy recourse there. For checkbox/radio/select elements, the change and input events behave practically the same.
It's also, natively, supported on more input types.
Which, input or change?
Even if you built your app explicitly for Preact today, if you have to add preact/compat for some reason in the future, the change in behavior could be unexpected and cause subtle problems that could be really difficult to debug, so, again, I really think it makes sense to be consistent with React here.
EDIT: just to clarify, if you're using onchange on text(area)-inputs for the debounce effect, you're probably better off using onblur, just to be on the safe side.
EDIT: there's also a note from @gaeron on React's issue tracker that seems relevant to this:
Different browsers do not always agree whether a change event should be fired for certain types of interaction.
Would you want your app to rely on this? As far as alternatives go,
onBlurin React gives you pretty much the same kind of behavior, so you can use it instead of browser鈥檚 `onchange.
Basically what I'm suggesting here.
@mindplay-dk In DOM-land the input event works consistently for every type of form control and is what you want in 99.9% of use cases. It works in every modern browser and even in older ones going back to IE11 (and probably even older than that). Personally I don't see many use cases for the change event and have never used it.
Now the tricky thing is that React decided to overwrite the change event and make it work exactly like input does, thereby deviating from the DOM :man_shrugging: This is a design decision that probably dates back to before React was announced and they likely couldn't change it with the amount of components they have at facebook. Remember that React has been in use at facebook for years before they went public.
I've always thought of Preact as supporting a subset of React - with preact/compat being the package you need if you want full compatibility with React.
Preact has never been just a subset of React and we don't advertise it as that. Instead we view it as the thinnest possible Virtual DOM abstraction on top of the DOM with a react-like API. That's the same text we have on preactjs.com.
EDIT: just to clarify, if you're using onchange on text(area)-inputs for the debounce effect, you're probably better off using onblur, just to be on the safe side.
Agree. The blur event is the one that is preferable in that situation :+1:
@marvinhagemeister I don't disagree with any of your assertions, but the problems I listed are still real - switching from React to Preact (which you encourage as optimal) or adding/removing preact-compat is very likely to create subtle bugs that are very difficult to isolate and debug, since the React community does use onchange and is taught to do so.
I don't know, I guess I can't really add anything new to the discussion - but if you want the transition from React to Preact to be smooth, and if you want preact-compat to be something you can just turn on or off, this doesn't really seem like the best decision. Just my opinion. I'll shut up now. 馃槣
@mindplay-dk We're currently working on our docs for X and I'll probably rewrite the Differences from React page completely. I guess instead of just saying that we're reusing the event system of the DOM, we should go more into detail what the differences are :+1: :100:
(it's mostly onChange vs onInput and onDoubleClick vs ondblclick)
since the React community does use onchange and is taught to do so.
wait really? that seems like a bad thing to teach given how it maps to native events, imo you'd want people to be somewhat aware of what react is doing for them
I guess instead of just saying that we're reusing the event system of the DOM, we should go more into detail what the differences are
Documenting the problems won't make the problems go away.
I'm sorry, I can't help myself! 馃槼
Real talk: I think you should document not only the differences - you also need to be clear about what the problems are: why/how these subtle differences can lead to subtle bugs and unexpected behavior when switching to/from React and/or preact-compat.
(Not that most people are likely to actually read this and remember it, but still.)
(I know, it's still obvious what I'm getting at here. Sorry.)
Most helpful comment
Found it!
In Preact it's
onInputinstead ofonChange