Skip to content
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

Fix movementX/Y polyfill with capture events #19672

Merged
merged 2 commits into from Aug 21, 2020
Merged

Conversation

@gaearon
Copy link
Member

@gaearon gaearon commented Aug 21, 2020

This is a blocker I need to resolve for #19648.

Our movementX/Y polyfill is currently broken with the modern event system if you use a capture event. This is because it diffs the screenX/Y with the last event's values, but now we have two synthetic events per one native event (due to capture and bubble phase). So we create an event in the capture phase, set its movementX/Y, and then we create another object in the bubble phase, and its movementX/Y is calculated to be 0 (because it is diffed with the event we just created earlier).

To fix this, I am pulling this logic out in one place and update both movementX and movementY values together and only if the native event has changed. This means we retain one last mouse event at a time (when the polyfill is used, which is IE11-only). Seems ok.

Test Plan

Added a test that previously failed.

I also manually tested by forcing the polyfill to always be used and running it with this fixture:

        <div style={{
          width: '100vw',
          height: '100vh',
          background: 'red'
        }}
          onMouseDown={e => {
            if (e.movementX !== e.nativeEvent.movementX) {
              console.error('noooooo', e.movementX, e.nativeEvent.movementX)
            }
            if (e.movementY !== e.nativeEvent.movementY) {
              console.error('noooooo', e.movementY, e.nativeEvent.movementY)
            }
          }}
          onMouseDownCapture={e => {
            if (e.movementX !== e.nativeEvent.movementX) {
              console.error('noooooo', e.movementX, e.nativeEvent.movementX)
            }
            if (e.movementY !== e.nativeEvent.movementY) {
              console.error('noooooo', e.movementY, e.nativeEvent.movementY)
            }
          }}
          onMouseMove={e => {
            if (e.movementX !== e.nativeEvent.movementX) {
              console.error('noooooo', e.movementX, e.nativeEvent.movementX)
            }
            if (e.movementY !== e.nativeEvent.movementY) {
              console.error('noooooo', e.movementY, e.nativeEvent.movementY)
            }
          }}
          onMouseMoveCapture={e => {
            if (e.movementX !== e.nativeEvent.movementX) {
              console.error('noooooo', e.movementX, e.nativeEvent.movementX)
            }
            if (e.movementY !== e.nativeEvent.movementY) {
              console.error('noooooo', e.movementY, e.nativeEvent.movementY)
            }
          }}
          onMouseUp={e => {
            if (e.movementX !== e.nativeEvent.movementX) {
              console.error('noooooo', e.movementX, e.nativeEvent.movementX)
            }
            if (e.movementY !== e.nativeEvent.movementY) {
              console.error('noooooo', e.movementY, e.nativeEvent.movementY)
            }
          }}
          onMouseUpCapture={e => {
            if (e.movementX !== e.nativeEvent.movementX) {
              console.error('noooooo', e.movementX, e.nativeEvent.movementX)
            }
            if (e.movementY !== e.nativeEvent.movementY) {
              console.error('noooooo', e.movementY, e.nativeEvent.movementY)
            }
          }}
        />,

Clicking and moving works as expected (no violations). There is a calculation bug every time after we move cursor outside the screen and bring it back, but this bug existed in 16 too, and I don't think it's worth fixing. (We'll remove the polyfill eventually anyway).

@gaearon gaearon force-pushed the gaearon:mouse branch from 8ef9b91 to 3e039e8 Aug 21, 2020
@codesandbox
Copy link

@codesandbox codesandbox bot commented Aug 21, 2020

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit f976c48:

Sandbox Source
React Configuration
@sizebot
Copy link

@sizebot sizebot commented Aug 21, 2020

No significant bundle size changes to report.

Size changes (experimental)

Generated by 🚫 dangerJS against f976c48

@sizebot
Copy link

@sizebot sizebot commented Aug 21, 2020

No significant bundle size changes to report.

Size changes (stable)

Generated by 🚫 dangerJS against f976c48

@gaearon gaearon merged commit 90d212d into facebook:master Aug 21, 2020
32 checks passed
32 checks passed
Facebook CLA Check Contributor License Agreement is valid!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_build Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_lint_build Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_build Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_build_prod Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_dom_fixtures Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_persistent Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_prod Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_prod_www Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_prod_www_variant Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_www Your tests passed on CircleCI!
Details
ci/circleci: RELEASE_CHANNEL_stable_yarn_test_www_variant Your tests passed on CircleCI!
Details
ci/circleci: process_artifacts Your tests passed on CircleCI!
Details
ci/circleci: process_artifacts_experimental Your tests passed on CircleCI!
Details
ci/circleci: setup Your tests passed on CircleCI!
Details
ci/circleci: sizebot_experimental Your tests passed on CircleCI!
Details
ci/circleci: sizebot_stable Your tests passed on CircleCI!
Details
ci/circleci: yarn_build Your tests passed on CircleCI!
Details
ci/circleci: yarn_flow Your tests passed on CircleCI!
Details
ci/circleci: yarn_lint Your tests passed on CircleCI!
Details
ci/circleci: yarn_lint_build Your tests passed on CircleCI!
Details
ci/circleci: yarn_test Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_build Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_build_devtools Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_build_prod Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_prod Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_prod_www Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_prod_www_variant Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_www Your tests passed on CircleCI!
Details
ci/circleci: yarn_test_www_variant Your tests passed on CircleCI!
Details
ci/codesandbox Building packages succeeded.
Details
@gaearon gaearon deleted the gaearon:mouse branch Aug 21, 2020
trueadm referenced this pull request in reactjs/reactjs.org Aug 28, 2020
lastMovementX = 0;
lastMovementY = 0;
}
lastMouseEvent = event;

This comment has been minimized.

@IDisposable

IDisposable Oct 28, 2020

Won't this GC root the event? This seems like a leak.

This comment has been minimized.

@gaearon

gaearon Oct 28, 2020
Author Member

It will root only one (the very last) mouse event, and only on IE11, so this should not be an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants
You can’t perform that action at this time.