-
Notifications
You must be signed in to change notification settings - Fork 47k
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
Declarative API for installing global DOM event handlers #285
Comments
Yes, I've wanted this for |
+1 on that, just encountered a case for that
If it fires on every component does it makes sense for it to bubble? |
I wanted this for mousemove and mouseup as well. :) We're thinking about a larger declarative event system that could do conflict resolution but we should probably get this in the mean time. Not sure about the API though. |
For mousemove and mouseup, I think @jordwalke was suggesting using ResponderEventPlugin… |
I'll also add that a way to bind to onbeforeunload declaratively could be helpful. |
Also will be cool to have context keyDown. Like context hokeys for keyboard driven apps. |
@Aetet Sadly though, all of them operate on the assumption of US/Western keyboard layouts, unless you're willing to avoid support for @spicyj @petehunt As for this specific PR, what about simply exposing it as Depending on the use-cases, I guess you could even do The mixins could even be implemented as an addon, although it kind of feels like a "native" implementation would be nice. |
Maybe it would be useful to consider a Flux Store-like solution here? Like some kind of onWindowResize: function(event) {
// do whatever you want in response to the resize event
},
componentDidMount: function() {
this.subscription = ReactEvents.subscribe(ReactEvents.constants.WINDOW_RESIZE, this.onWindowResize);
},
componentWillUnmount: function() {
this.subscription.remove();
} |
A couple of additional data points on this - the demo in http://kentwilliam.com/articles/rich-drag-and-drop-in-react-js mentions having to drop out of react events to do document listeners for mouse movements. I've got a small module I put together for handing hotkeys that reaches into a bunch of React internals in order to produce synthetic keyboard events for document key events: https://github.com/glenjamin/react-hotkey/blob/master/index.js - providing a neat top-level listener that can be subscribed to, but forcing components to manage their own subscriptions' lifecycle seems like a reasonable tradeoff to me. |
An API to hook events into the component events, like @glenjamin described, to produce synthetic events would be a nice thing to have.
I would recommend a look at the Bacon.js wrappers. Maybe a fromCallback binder would be great, too? It needs to be useable declaratively ( like other events )
and when could it be registered?
i think that is basically what @nick-thompson and @syranide were saying. |
👍 For React support |
👍 |
4 similar comments
👍 |
👍 |
👍 |
👍 |
👍, I'd like something like this : var Modal = React.createClass({
componentDidMount() {
React.addEventListener(document, "keyup", this.handleShortcuts)
},
componentWillUnmount() {
React.removeEventListener(document, "keyup", this.handleShortcuts)
},
handleShortcuts(eventObject) {
switch(eventObject.which) {
case 27:
this.props.hide()
break
// …
}
}
// …
}) |
👍 |
👍 |
1 similar comment
👍 |
I'm looking for a solution like this as well! As in, having a standard DOM event called, say,
Currently the React event system feels quite exclusive of any 3rd party libs. |
I think #285 (comment) is a pretty good idea, but its kind of messy. class App extends React.Document {
handleResize() { this.forceUpdate() }
render() { return <div onDocumentResize={this.handleResize.bind(this)}/>; }
}
React.render(<App/>, document.body, {delegateEvents: true}); Kind of off topic, but this could be related to work making react handle being mounted on document.body function more sensibly... If it were safer to mount react on the document body you could delegate body events by default. |
@nelix do events only propagate but not bubble in your proposal? |
+1 to |
Couldn't agree more with all above poster, +1 |
+1 to @brigand's suggestion |
Yes, of course, it can't put events that are not listened by React on the same phase, it solves the issue for use-cases like listening to a click outside & mousemove/up though. |
Is this still being considered? It would be nice if React could somehow encourage users to do small tasks optimally like when changing a header background color based on scroll position. I encountered this on a project, and my instinct was to use This is the component I ended up with which also included support for passive event listening: https://gist.github.com/tribou/d405436286807eeff669ad4d909331f5 |
I've been wanting this as well. Lacing native event listeners into component lifecycle events feels very haphazard and opens up the potential for memory leaks & exceptions if steps aren't taken to properly tear down the listeners during unmount. |
No near-term plans for this, sorry. |
Right now, the only way to respond to "outside world" events is to leave the React's event system and add a native DOM listener. This is bad, since it will require more mental overhead when you have to work with this (you need to think about your event listener receiving a native event, or a react synthetic event). It will also simply not be possible for computed It also makes it very hard for react events handlers to interrupt the DOM handlers (This issue is mentioned above). Consider the following example, where it's not intuitive why the React listener can not stop propagation to the class ExampleComponent extends React.Component {
render() {
return (
<div onKeyDown={(e) => e.stopPropagation()} />
)
}
}
document.addEventListener('keydown', () => {
alert('why does this still fire?')
})
ReactDOM.render(
<ExampleComponent name="react"/>,
document.getElementById('react')
) An example for when you want to deal with outside events is a simple drawing tool, that must listen on There are a lot of solution ideas - most of them are tied to DOM specific features like I can think of a new public API, something like an The EventRoot get involved when triggering a two-phase dispatch. It respects the This API should help to further abstract the fact that React will listen on For the above example, you'd only have to replace I'd love to hear what you think about this and how I could help shape the future of React's event system. 😊 |
+1 |
With the advent of portals in React 16, it's the first time for me that React's event system has felt so dramatically different to that of the DOM. As I raised in #10962, the fact that events bubble through portals is very handy and so far seems to make logical sense, but is not something that works nicely with the current fallbacks to adding DOM events. I think this divergence makes the need for such an API into React's event system even more relevant now. |
More reliable when using virtual event bubbling (e.g. portals), but as workaround to noted issue of document-level event binding, need to stop propagation. See: facebook/react#285
More reliable when using virtual event bubbling (e.g. portals), but as workaround to noted issue of document-level event binding, need to stop propagation. See: facebook/react#285
Actually, none of the solutions mentioned above were sufficient for me, and I thought I had a pretty general case. I needed some simple global hotkeys. Binding them natively on document in For anyone having the same problem, here's a neat little solution/trick I came up with that might help you and has not been offered in this thread or anywhere for that matter: Bind it twice - once on document, and once at the top of your react tree. The document handler checks if
This can of course be applied to any other events, like clicks etc.. A very simple mockup of the ideafunction onKeyDown(e) {
// Handle global keydowns. !Warning: may receive native or synthetic events
}
function onKeyDownNative(e) {
// Or whatever assertion works for your usecase, whatever is
// "outside" of the react tree.
if (e.target === document.body) {
onKeyDown(e);
}
}
// Wrap this around the entire app
class HotkeyListener extends React.Component {
componentDidMount() {
document.addEventListener("keydown", onKeyDownNative);
}
componentWillUnmount() {
document.removeEventListener("keydown", onKeyDownNative);
}
render() {
// Listens to any propagated synthetic keydown events
return <div onKeyDown={onKeyDown}>{this.props.children}</div>;
}
}
ReactDOM.render(
<HotkeyListener>
// This input will propagate and trigger global key event through the synthetic event handler
<input type="text" />
// This one will not
<input type="text" onKeyDown={(e) => e.stopPropagation()} />
</HotkeyListener>
, document.getElementById("app")) Working demo on Codepen |
(Wow, no progress in five years? Doesn't Facebook itself support keyboard shortcuts and dismissing popups by clicking outside them?) I got bitten by this today, when I refactored something from listening to keypresses on an |
In current React, it would make sense to offer this as hooks, which also do update batching on all listeners of the type. This would be a significant value add, as React is serving as a hub for all of our own code and react packages we depend on... to provide efficient updates. |
Regarding #285 (comment) in particular, we're switching React 17 to register events at the roots, which solves that particular case. |
perhaps close it already? |
#284 reminded me that one thing I've sometimes wanted is to install a handler on window for
keypress
(for keyboard shortcuts) orscroll
. Right now I can just dowindow.addEventListener
incomponentDidMount
but since React is listening already, it would be nice if there were some way for me to intercept those events. (In addition, receiving normalized synthetic events is generally more useful.)The text was updated successfully, but these errors were encountered: