react prevents parent container from scrolling
Recently, a problem occurred when I was doing code migration. I found that a custom scrollbar component I wrote before had a bug, and the parent container would also scroll when scrolling.
Look at the code, the code has been simplified
export default ()=>{ return return ( <div className={classNames(getCls('container'), ? 'active' : '', className)} ref={scrollDOMRef} onWheelCapture={(e: any) => { (); if ( < 0) { // Upward setDragY(dragY - dragSpeed); } else { // Down setDragY(dragY + dragSpeed); } }}> </div> ); }
Since the parent container will scroll, just block the default behavior();
, but useless.
Here I guess that because react events are synthetic events, all events are registered on the document, so the default behavior that causes blocking is not blocked to the parent container.
Then use the native one.
useEffect(() => { if () { ('wheel', (e) => { (); if ( < 0) { // Upward setDragY(dragY - dragSpeed); } else { // Down setDragY(dragY + dragSpeed); } }); } }, []);
When using native events and react events together, be careful and consider preventing bubbles, because it may cause react synthesis events to fail.
Then will it be fine after doing this?
really
The parent container is not scrolling
But I fell into the closure trap of react
The registration function was not updated in time, and the closures of dragY and dragSpeed resulted in a bug.
So what should I do?
useEffect(() => { if () { ('wheel', (e) => { (); if ( < 0) { // Upward setDragY(dragY - dragSpeed); } else { // Down setDragY(dragY + dragSpeed); } }); } }, [, dragY, dragSpeed]);
Another problem has emerged
Each time, the previous event should be destroyed and then registered.
Otherwise, multiple events will trigger at the same time and cause a bug.
useEffect(() => { const handle = (e: any) => { (); if ( < 0) { // Upward setDragY(dragY - dragSpeed); } else { // Down setDragY(dragY + dragSpeed); } }; if () { ('wheel', handle, { passive: false, }); } return () => { if () { ('wheel', handle); } }; }, [, dragY, dragSpeed]);
passive
When passive is false, the browser only knows whether preventDefault has been called after executing the callback function. If preventDefault is not called, then the default behavior is executed, which is scrolling. This will cause the scrolling to be unsmooth.
Passive is true, which means telling the browser not to call preventDefault, and the browser just executes scrolling directly, without considering the callback function.
At this time, even if you call preventDefault in the callback function, it will not take effect.
mdn says that in some browsers (especially Chrome and Firefox), if you listen to window, document or touchstart and touchmove on it, the passive will be set to true by default.
I still need to remind everyone that when you don't need to call preventDefault, listen to scroll or touchmove and set passive to true
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.