-
Notifications
You must be signed in to change notification settings - Fork 2
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
Use passive event listener for touchmove (to prevent scrolling while swiping) #2
Use passive event listener for touchmove (to prevent scrolling while swiping) #2
Conversation
src/inner-slider.js
Outdated
@@ -188,6 +195,13 @@ export class InnerSlider extends React.Component { | |||
// this.props.onLazyLoad([leftMostSlide]) | |||
// } | |||
this.adaptHeight(); | |||
|
|||
if (prevProps.touchMove !== this.props.touchMove) { | |||
const method = touchMove ? "add" : "remove"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is touchMove defined? Should be this.props.touchMove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, fixed!
8b951b2
to
adbd56e
Compare
@@ -704,7 +714,6 @@ export class InnerSlider extends React.Component { | |||
onMouseUp: touchMove ? this.swipeEnd : null, | |||
onMouseLeave: this.state.dragging && touchMove ? this.swipeEnd : null, | |||
onTouchStart: touchMove ? this.swipeStart : null, | |||
onTouchMove: this.state.dragging && touchMove ? this.swipeMove : null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you also need to preserve this logic around this.state.dragging
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added it back in but in a slightly different manner to work around another iOS Safari quirk (touch listeners registered by other touch listeners don't seem to be able to be made non-passive).
src/inner-slider.js
Outdated
@@ -97,6 +97,11 @@ export class InnerSlider extends React.Component { | |||
slide.onblur = this.props.pauseOnFocus ? this.onSlideBlur : null; | |||
} | |||
); | |||
|
|||
if (this.props.touchMove) { | |||
this.list.addEventListener("touchmove", this.swipeMove); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you remove { passive: false } because it's the default? I'd probably keep it and add a comment to explain that we need passive set to false to allow preventDefault and link to https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener for more details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I felt that it was unnecessary to leave it in, as false is the default. I can add it back in to guard against a future change to the default (although I'd guess it'd be very unlikely to happen)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added it back in and added note
Previously touchmove handler was registered from within a touchstart event. Seems as though handlers registered from within touch handlers are always passive, regardless of the passive param. Instead we keep the touchmove handler around, and return early if not in a dragging state.
82def76
to
878b61b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me! Awesome work @xanido !
oh one last thing, might need to clean up touchmove in |
const method = this.props.touchMove ? "add" : "remove"; | ||
// swipeMove calls preventDefault which only has an effect on non-passive events | ||
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener | ||
this.list[`${method}EventListener`]("touchmove", this.swipeMove, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isnt there a chance that there is a listener thats created but not removed here?
D’oh you’re right! Sorry thanks for catching that, will update
…On Fri, 31 May 2019 at 1:33 pm, Matt Colman ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In src/inner-slider.js
<#2 (comment)>
:
> @@ -188,6 +195,13 @@ export class InnerSlider extends React.Component {
// this.props.onLazyLoad([leftMostSlide])
// }
this.adaptHeight();
+
+ if (prevProps.touchMove !== this.props.touchMove) {
+ const method = touchMove ? "add" : "remove";
is touchMove defined? Should be this.props.touchMove?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#2?email_source=notifications&email_token=AAGUQWFSDKA6T3BQDOBZ2J3PYCMBLA5CNFSM4HRQOHTKYY3PNVWWK3TUL52HS4DFWFIHK3DMKJSXC5LFON2FEZLWNFSXPKTDN5WW2ZLOORPWSZGOB2GP4WI#pullrequestreview-244121177>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAGUQWCMC4B4NC3T3QTTC2LPYCMBLANCNFSM4HRQOHTA>
.
|
@@ -118,6 +127,11 @@ export class InnerSlider extends React.Component { | |||
this.callbackTimers.forEach(timer => clearTimeout(timer)); | |||
this.callbackTimers = []; | |||
} | |||
if(this.props.touchMove) { | |||
this.list.removeEventListener("touchmove", this.swipeMove, { | |||
passive: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good to check if animating
is true, if its true you can have passive true which will improve performance
as you are promising the handler won't call preventDefault
to disable scrolling.
// swipeMove calls preventDefault which only has an effect on non-passive events | ||
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener | ||
this.list.addEventListener("touchmove", this.swipeMove, { | ||
passive: false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good to check if animating
is true, if its true you can have passive true which will improve performance
as you are promising the handler won't call preventDefault
to disable scrolling.
why do you need to disable vertical scrolling when swiping ? |
That's the expected behaviour, if you are trying to swipe horizontal it won't also allow you to scroll vertically. |
This small patch restores react-slider's ability to disable vertical scrolling when swiping through a slider on iOS.
Seems the
touchmove
event listener that React adds (when using the React's event system via event props) is not configured as a non-passive listener. iOS (starting with iOS 11.3) has made all root document touch event listeners passive by default to improve scrolling performance. React's event system attaches event handlers to the document root, which will result in a passivetouchmove
listener on iOS, which in turn means thatpreventDefault()
has no effect.The proposed solution in facebook/react#2043 should fix the issue, but for now adding the event listener directly to the node also solves the problem.
Please note, the
{passive: false}
in the addEventListener call in this PR is not technically necessary as only document root event listeners are passive by default on iOS, but it does explicitly communicate the intent.