I'm not sure if @nhatkhoa here is having the same problem as I do. But I'm trying to indeed prevent the page from scrolling when the bottom of the scrollbar is reached.
Currently I'm fixing this like this:
I put a ref on the scrollbars:
<Scrollbars ref="scrollBars">
{list}
</Scrollbars>
And I add a custom 'mousewheel' listener to the view ref of the scrollBars.
// simplified, not cross browser proof..
this.refs.scrollBars.refs.view.addEventListener('mousewheel', (evt) => {
const { scrollHeight, clientHeight, scrollTop } = this.refs.scrollBars.getValues();
// Prevent if we're at the end
if (evt.deltaY > 0 && (scrollHeight - clientHeight <= scrollTop)) {
evt.preventDefault();
}
}, false);
But this is far from ideal..
Did somebody encountered this problem before / like to share their thoughts on my solution?
Hey, this might work:
var PreventPageScrollingScrollbars = createClass({
componentDidMount() {
window.addEventListener("mousewheel", this.handleWindowWheel, false);
},
componentWillUnmount() {
window.removeEventListener("mousewheel", this.handleWindowWheel);
},
handleWindowWheel(event) {
const { top } = this.refs.scrollbars.getValues();
// When the bottom is reached and we're scrolling down, prevent scrolling of the window
if (top >= 1 && event.deltaY > 0) event.preventDefault();
},
render() {
return (
<Scrollbars ref="scrollbars" {...this.props}/>
);
}
});
You can then use this component:
<PreventPageScrollingScrollbars>
{/* Your content */}
</PreventPageScrollingScrollbars>
Yeah that is kindof what I did right? Except I did not wrap it in a component. Good idea, thanks :)
FYI top >= 1 && event.deltaY > 0 does not work all the time. It seems like top is never 1 in my implementation but always something like 0.992 of 0.9997. Checking on top >= 0.99 or adding the delta to the current position does the trick: (scrollHeight - clientHeight <= scrollTop + event.deltaY) && evt.deltaY > 0.
I'm guessing this has something to with my retina screen because it works fine on my extended monitor. Took me a while to figure out that there was actually a difference when I dragged my window to my other screen... I can imagine this might also cause other problems btw.
On using @malte-wessel method , I'am getting this error:
Uncaught TypeError: Cannot read property 'scrollbars' of undefined
I'll close this for now. Please reopen if still not working...
Since the "how to achieve this" is not really obvious by reading this thread, I'll report my fully working solution.
That said, I reckon this should probably be an optional property of the component: windowScroll={false} to make it work out-of-the-box (despite not working on mobile, as long as it is documented).
class MyComponent extends React.Component {
componentDidMount() {
this.refs.wrapper.addEventListener('wheel', e => this.handleWindowWheel(e), false);
}
componentWillUnmount() {
this.refs.wrapper.removeEventListener('wheel', e => this.handleWindowWheel(e));
}
handleWindowWheel(e) {
const { scrollHeight, clientHeight, scrollTop } = this.refs.scrollbars.getValues();
// When the bottom is reached and we're scrolling down, prevent scrolling of the window
if (e.deltaY > 0 && (scrollHeight - clientHeight <= scrollTop + 1)) e.preventDefault();
}
render() {
return (
<div>
<Scrollbars ref='scrollbars'>
<div ref='wrapper'>
</div>
</Scrollbars>
</div>
);
}
}
I need the <div ref='wrapper'> because this.refs.scrollbars doesn't exist during mount, but if it is part of the code, it should be worn by the actual <Scrollbars /> component wrapper.
Sidenote:
If you get the following warning:
[Violation] Added non-passive event listener to a scroll-blocking 'wheel' event. Consider marking event handler as 'passive' to make the page more responsive. See https://www.chromestatus.com/feature/5745543795965952
Unless I'm wrong, this is to be ignored, because this means one will never user event.preventDefault() which is not our case here. :smile:
Most helpful comment
Since the "how to achieve this" is not really obvious by reading this thread, I'll report my fully working solution.
That said, I reckon this should probably be an optional property of the component:
windowScroll={false}to make it work out-of-the-box (despite not working on mobile, as long as it is documented).I need the
<div ref='wrapper'>becausethis.refs.scrollbarsdoesn't exist during mount, but if it is part of the code, it should be worn by the actual<Scrollbars />component wrapper.Sidenote:
If you get the following warning:
Unless I'm wrong, this is to be ignored, because this means one will never user
event.preventDefault()which is not our case here. :smile: