[zoom] make wheel event active by default. fixes #455 #456
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The Problem
Chrome 73 made
wheel
event listeners passive by default. A passive event listener is an event listener that does not callpreventDefault()
on the event. This is great because it makes scrolling faster. https://developers.google.com/web/updates/2019/02/scrolling-intervention.Google found 98% of
wheel
andmousewheel
event listeners do not callpreventDefault()
. So the trade off here of faster scrolling on the web for the relatively small cost of 2% of listeners need to opt-in to making the wheel listener active. Unfortunately,<Zoom />
falls in the 2% here.The recommended fix
Convert event listeners that rely on
preventDefault()
to active.But what about React?
Folks in react-land probably aren't used to writing
addEventListener()
these days. The more usual pattern is to addonWheel={this.handleWheel}
prop. So how do we make an event listener active in React? My observed behavior of React is that it registers event listeners without a default value for passive (I could be wrong about this, I was running in circles in the React codebase). Ideally React would support the ability to set the passive value. Until then, we'll have to fall back to rolling our own addEventListener + removeEventListener.The solution
Keeping the default behavior
The default behavior for
<Zoom />
will be to add an active event listener incomponentDidMount
and remove itcomponentWillUnmount()
and callpreventDefault()
on wheel events. This matches the previous default behavior, but requires the removal of a prop to get rid of the console warning from Chrome.The breaking change
If you update to this version of @vx/zoom, you'll just have to remove
onWheel={zoom.handleWheel}
and the warning will go away and everything should work as before. The diff is small:<MyComponent - onWheel={zoom.handleWheel} />
Opt-in to passive on wheel event listener
The upside here is you now have a way to opt-in to passive on wheel event listener. This will not call
preventDefault()
Further reading
Changelog
💥 Breaking Changes
<MyComponent - onWheel={zoom.handleWheel} />
📝 Documentation
Thanks to @j1mie for bringing this to my attention.