-
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
React shouldn't bind wheel or touch events to the document. #1254
Comments
This would also definitely fix our initializeTouchEvents problem. I don't know the perf impacts of not bubbling to document though. |
Anyone picking this one up? Otherwise, I would like to give it a go :-). |
It would also fix the problem I'm having here: Arguably not a bug but unexpected and undesirable for me. |
@SanderSpies you're exactly who I had in mind for this! :) |
petehunt: great :) Potential scenario's I'm seeing:
So for these event types there will be more then one event listener
I guess we always want to use the parent element
Which would imply we would also need to remove/add event listeners on the fly, not sure if we already do that I'm thinking of adding something like 'bindLocally' at the event plugins level like: onTouchMove: { Good idea? Bad idea? Missing stuff here? |
It's really a function of the topLevelType Right now I don't believe we ever remove listeners. |
@spicyj I wrote that code a bit too hastily I guess. Should have been touchMove, also notice the onDragOver + onDragOverCapture that I forgot to correct... |
Currently the event listeners are attached before React inserts the nodes into the DOM. So I was wondering how I should handle this. I was thinking of letting ReactEventEmitter.listenTo create a 'bag' for local events, that is later used by a new function (addLocalEventListeners?) which is called by ReactComponent._mountComponentIntoNode. Thoughts on this? |
Are you sure it's before the DOM nodes are created? Regardless, probably you want to tie it to the transaction -- you can see how ReactReconcileTransaction stores a queue of componentDidMount callbacks (ON_DOM_READY_QUEUEING/ReactMountReady) and a queue of listeners to put (PUT_LISTENER_QUEUEING/ReactPutListenerQueue). If the put listener queue can't easily be modified to do what you want (though I'm guessing it can), you can make a new transaction wrapper and add it to the list there. |
Is this still being investigated? |
This problem was also noticed by former Edge/IE engineer Justin Rogers, who now works with y'all at Facebook. 😃 React's technique of adding a global To demonstrate, I put together a little sample application based on There are three versions of the app: 1) no In Firefox and Chrome, there is no difference between (2) and (3). However, in Edge and Safari, React's technique of adding the global Note that this optimization only applies to certain kinds of scroll events like mousewheel scrolling, not necessarily two-finger touchpad scrolling, clicking-and-dragging the scrollbar, or keyboard-scrolling. So you may need to use a real mouse to reproduce. It also may apply to It's kind of a subtle issue, so I also made a quick video demonstration: https://youtu.be/6Ckepx3wPPE |
Update: added I compiled the results into a table for those who want to see a browser-by-browser breakdown. |
We just published a code dive into React event system (thanks @spicyj and @kentcdodds!) |
Just read this article and found my way here. I've got some bandwidth now that the number input issue is more or less wrapped up. Is anyone working on this? Anything I should keep in mind before I get started? |
Working on a fix here: This change allows ReactBrowserEventEmitter, which is responsible for attaching event listeners, to make the decision on a case-by-case basis as to what events should be attached to the document vs the element itself. I still haven't gotten into touch events or serious wheel testing, but I can confirm that it gets rid of the window scroll jank in @nolanlawson v2 example Time to find a mouse with a wheel! |
@nhunzaker We should chat about this strategy. There are several considerations here.
|
Absolutely. Is reactiflux, the discord room, best? Really any medium is fine. Re 1: Are there any known bottlenecks that you could point me to? Re 2: Totally, and hard to test. It would be good to get some DOM fixtures in place as we uncover issues. That was going to be my next step here. |
Probably best to start here. I just wanted to highlight those issue so you're aware.
|
@sebmarkbage I recently had a few PRs merged that remove some of the work in BrowserEventEmitter doing support checks we don't need. Next I'm going to see what kind of savings we actually get by just assigning an event listener for every supported event. Without changing things too much, I want to figure out what's slow, eliminate that work, then evaluate reworking ReactBrowserEventEmitter with less moving parts (and I better understand what's happening). I'm also curious if we can reduce the number of calls to Is that a reasonable approach? |
Restricting the set of "prefer local listeners" to FWIW, in case you don't want to go to the trouble of buying a mouse with a wheel, I've found that two-fingered scrolling on a touchpad usually exhibits identical behavior. |
@nolanlawson Thank you for the guidance! I have a mouse with a wheel (thank goodness for conference swag), but I wasn't sure about two-fingered scrolling, that's really good to know. @sebmarkbage The only hiccup I'm hitting now is that to-string rendering (at least running tests against the feature flag:
The problem is that
So I had a few questions/ideas:
transaction.getReactMountReady().enqueue(attachListeners, this); If we did this, what do you think about moving all of the local listener logic out of Then, possibly, we could eliminate the unmount work here: |
|
Mentioning #2043 here as "probably related". 🙂 |
This might be related to #14856 or become more important since that chrome change. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution. |
This has been implemented and will go out in React 17. |
--- #1254 added inference for hooks loaded from globals. This is the only time we need to generate a type equation assigning `lval` to a resolved`Hook` type. @gsathya Would love to get your feedback here on the change. From my understanding, this change is technically incorrect, since the type equation we generate should be dependent on the `callee` type (i.e. `Hook` if callee is a hook, `Function` if callee is a function). Would the next step be to consolidate `Hook` and `Function` types? ```js type Function { ... isHook: boolean, // set by inference } type FunctionSignature { isHook: boolean, // set when adding to ShapeRegistry } ```
React binds touchmove, touchstart, touchend, touchcancel and wheel handlers to the document. When the user tries to scroll the browser needs to execute these event handlers to ensure event.preventDefault() was not called. This means scrolling will stall while JavaScript is executing.
Chrome has a fast-path that checks whether the coordinate where the touch event happens has touch listeners (https://plus.google.com/+RickByers/posts/cmzrtyBYPQc). If there are no listeners Chrome can allow the scroll to happen even if the main thread is blocked on JavaScript.
We should bind our listeners for these events directly to the node which requires it. That event handler can then dispatch the event to the standard React top level event system. Then it will bubble/capture just like everything else and be visible to all event plugins.
The text was updated successfully, but these errors were encountered: