-
Notifications
You must be signed in to change notification settings - Fork 47.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Play Nicely with The DOM Event System (because it's legacy anyway) #4751
Comments
I'm not entirely sure what you're suggesting and I'm not familiar with ReactNative. I see two versions of ReactDOM; one being the barebones "as-is DOM" implementation where you expose the DOM as it is (and play nice with external events). But I'm not sure what users can realistically do to fix some of the more broken aspects of the DOM event system in this model though? Perhaps it doesn't really matter that much... The other is a more reimagined implementation of the DOM (managed inline styles, etc). It would not map DOM events 1:1, some events no longer bubble (like Both have their own merits, with the second sounding more of a community project to me. Perhaps this made no sense to what you're suggesting though :) |
As someone who has being struggling with integrating non-standard DOM events into react app I would like to share my humble opinion on the subject. I find it really unfortunate that react attempts to normalize DOM event system because:
I think it would be a lot better if React exposed DOM events as is and also provided custom event system separate from it. It could be dealt simply by choosing different naming convention for event handlers or IMO it would be even better to employ similar hooks abstraction as virtual-dom as it makes it really easy to define & share custom hooks like |
The problem is that I think that the DOM events and a custom event system will never integrate well. You can already see this in frameworks since the jQuery days. You can also see this in the DOM itself where events doesn't cooperate between iframes. They're whole boxes that steal the events and doesn't bubble for example. For example, the responder event system will need to conditionally block certain events from occurring elsewhere. That's why I think that a good custom event system is eventually going to be mutually exclusive with integrating well with the DOM event system. Basically, mixing two in the same box/window/frame is probably going to lead to a bad time regardless and is likely not going to be supported. It's easy to say that virtual-dom does the right thing because it just offloads the problem to someone else to solve. Once you start trying to solve these interaction problem it gets messy. Custom hooks into a global namespaces becomes a compatibility nightmare when the same name is used in slightly different versions and slightly different packages. Great if you write all your own components but not great if you're trying to cooperate in an ecosystem or large company. We could potentially make scoped extensions somehow, but it seems better to just wrap your commonly used components. Opting into using |
I was not necessarily suggesting integrating them but rather providing two levels for users to hook. For most common cases higher level custom event system will work fine, this is also what we prefer to use when possible. But if there is something that react team has not added support yet it is pretty much impossible to hook up into that higher level tire.
What I meant to say it provides good low level foundation that you can build say custom event system on top and ship all integrated solution. But it will also allows custom additions to the system. Sure it can get messy if you try to integrate hooks that don't work with each other, but I'd argue it's better than having no way to extend.
I don't follow here what do you refer to when you say "global namespace" ? Hooks don't reserve any names you box prop values with hooks so there is no naming conflicts as it's by identity rather than name. Maybe I misunderstood what you said though.
It's not always that easy I'm afraid. For example we use bunch of non standard DOM swipe events (see #4645 there are examples) to allow interaction with various UI entities. There is no single container makes sense across the board UI entities it's being used so boxing event hooks into special component does not quite work all that well. There is also cases where we use other custom events with swipes so you either add yet another container or start mixing non of which is a great solution. At the end of the day we end up implementing poor mans version of Hooks on top of react. Which works sort of but there are number of limitations that make it less ideal. I'm happy to share code illustrating these if there is an interest. |
@Gozala Yea, that is basically what this issue is meant to address. You would have two different View systems. One that is just pass-through to the DOM, and one that is an abstraction layer with a built-in richer event system.
By global name I mean the namespace on We could potentially have a whitelist for things that doesn't get special logic. E.g. just SimpleEventPlugin is allowed. That way it is not possible for two different component systems to collide in terms of logic. It is either on or off. However, we might need to break them between versions to be able to intercept the event system for events that we have special logic around, or special synthetic events.
You can use mixins to reuse the same logic on all your base components. You can also have a component that wraps the bubbled events inside your base components. E.g. If you're like Facebook/Netflix/Yahoo etc. and build your abstractions on TOP of the DOM this is easy because you end up with a few bottom layer primitives that you build everything else on. However, if you're like Mozilla/Polymer and build all your abstractions into the DOM, this is a bit of a pain because you have to wrap them every time you add a new abstraction. The Facebook/Netflix/Yahoos of the world can't build our abstractions into the DOM because we can't wait for a new cross-browser event that plays nicely with the rest of the DOM event system. E.g. Apple's "3D Touch" would need some integration with other DOM events like However, it seems fair that we should decouple that event system so that it become easier to use DOM-heavy abstractions. |
I think understand what you were saying, it's just I think you're misunderstanding how hooks actually work though. The prop name is irrelevant in that system what is relevant is the Hook with which property value is boxed with, here is an example: html.div({
foo: onClick(function(event) {
alert('hello hook');
})
}) In fact you could have two different event handlers for the same event as well, just add One thing possibly jsx could desugar to could be: <Foo onClick ={handler} />
Foo({[onClick.id]: onClick(handler)}) Assuming hooks use id's that are symbols (or namespaces strings you should be able to avoid conflicts). Elm actually uses lists instead of maps to avoid naming conflicts all together.
Just to be clear I was suggesting hooks as the low level API that on could build a higher level event system on top. I suspect higher level API will likely still have naming conflicts issue unless you do want to completely rework the API.
This is more or less what we do, but find it really cumbersome because I can see only two options in how
Things are actually little worth for us because we also use custom elements / attributes some of which need to be set before node is in the tree otherwise they don't work and combination of these issues makes it really difficult to pull it of.
The reason I want a better hooks to the DOM is in fact so that we (at least one team at Mozilla) would like could to higher level abstractions that expose more APIs that standard DOM does. It's just really difficult to do today given the API at hand. I suspect that Facebook / Netflix / Yahoo don't run into the same problems as it's less likely they are experimenting with a custom DOM APIs that aren't implemented anywhere yet. Anyway I did not implied that React should do what virtual-dom library does, I was mostly trying to say Yes please have a two layered event architecture so we could add support to events that react does not. |
@Gozala Thanks a lot. This is great feedback! It's a slightly different take (and more thoroughly thought through) than we've heard before. I've considered having a special element that can register event listeners but doesn't actually contribute to the DOM. <tr><EventHandler onClick={...}><CustomTd /></EventHandler></tr> I've been wanting that for a while and it would be trivial for us to add since we have our own custom event bubbling but without that it's tricky. It would be nice to have special DOM elements that are non-semantic contributions as well. That's one of the problems we have with Web Components. |
I'm glad it I could help ;)
That would be really great! I actually tried to do a version of
Another alternative could be something along the lines what we use to workaround whitelist of custom event / attribute / properties. We basically have a function that takes a This is how it looks to use this API: On major limitation that we still struggle with is that (which is on the part Gecko limitation) is that some attributes / properties need to be set up before node is injected into a document (In the end we end up using Maybe React could expose something along those lines ? Note that this would avoid name collision as props are scoped to a custom defined elements (unless your custom prop does already collides with name taken by react). This also handles custom anything problem not just events or attributes. Composition is not ideal but little better than with plain containers cause some of the custom props implementations could be reused (see https://github.com/mozilla/browser.html/blob/master/src/browser/iframe.js#L53) P.S.: @vjeux mentioned you've being thinking about some other stuff that we've being struggling with. I personally have being trying to move all of the app code into web-worker to keep only a renderer in the main thread. I'd be happy to chat about that if there is a good venue for it. |
That seems like a too generic approach to me, especially when you consider overhead of components. It also seems to me that it kind of breaks down in non-trivial cases.
That doesn't seem very nice at all. It also breaks component isolation in a way, I shouldn't reach inside opaque components, but I should attach event handlers without their permission? Wouldn't it make more sense with an approach along the lines of:
That way generic components could instead pass the events along to wherever it should go. Say you have a button with a decorative frame, the decorative frame shouldn't respond to events but with the proposed solution there doesn't seem to be a way around it? |
That's the problem with event bubbling in general and this doesn't make that worse. It is just a hassle to add listeners to every little node that may or may not be capturing something. You can use pointer-events: none to make non-hit target surfaces like your border. I think that this is a problem that goes much deeper into the DOM model. Ideally you would render hit targets completely separately from rendering IMO.
|
Having an event system that isn't specific to the DOM would also help non DOM renderers easily add their events to React. Brought this up in reactjs/react-art#67 |
Currently React implements its own plugin system and event bubbling rules. This is important for systems like the responder system since the DOM event system is incapable of implementing proper event negotiation support.
However, on desktop, we don't really take full advantage of our custom event system other than to polyfill mouseenter/leave and implement more bubbling.
There are plenty of other things that are wrong with the DOM but instead of patching it, maybe it would be better to build a new view system on top of the DOM that integrates with the custom event system. Similarly to how React Native handles things.
That way, the lowest level could just do what the DOM would do, however broken it may be.
Question though: How do we handle things like onChange?
cc @spicyj and @syranide since I know you always wanted this.
The text was updated successfully, but these errors were encountered: