React: Prevent scroll when modal is open
in functional component for when mount or unmount
useEffect(() => {
document.body.style.overflow = 'hidden';
return ()=> document.body.style.overflow = 'unset';
}, []);
or when show
is change or etc
useEffect(() => {
show && document.body.style.overflow = 'hidden';
!show && document.body.style.overflow = 'unset';
}, [show ]);
In functional components if the browser move due to hiding/showing scroll.
useEffect(() => {
if (show) {
document.body.style.overflow = 'hidden';
document.body.style.paddingRight = '15px';
}
return () => {
document.body.style.overflow = 'unset';
document.body.style.paddingRight = '0px';
};
}, [show]);
Use state to track if the Modal is open and only hide scroll if it's true. Since you're using document.body.style.overflow = 'hidden'
in componentDidMount
, the component still gets mounted which calls the lifecycle method that hides the scroll on body.
export class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
open:false
}
}
componentDidMount() {
if(this.state.open){
document.body.style.overflow = 'hidden';
}
}
componentWillUnmount() {
document.body.style.overflow = 'unset';
}
render() {
return (
<React.Fragment>
{this.props.showAt ?
this.props.show ?
<div style={style} className={`${this.props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!this.props.showAt ? styles.modalWhiteFixed : ""}`}>
{this.props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{this.props.children}
</div>
: null
:
this.props.show ?
<div className={`${this.props.className} ${styles.modal}`}>
<div style={style} className={`${this.props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!this.props.showAt ? styles.modalWhiteFixed : ""}`}>
{this.props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{this.props.children}
</div>
</div> :
null}
</React.Fragment>
)
}
}
Here is a custom hook you can use for functional components.
import { useEffect } from 'react';
export const useDisableBodyScroll = (open) => {
useEffect(() => {
if (open) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
}, [open]);
};
export const Modal = (props) => {
useDisableBodyScroll(props.show);
return (
<React.Fragment>
{props.showAt ?
props.show ?
<div style={style} className={`${props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!props.showAt ? styles.modalWhiteFixed : ""}`}>
{props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{props.children}
</div>
: null
:
props.show ?
<div className={`${props.className} ${styles.modal}`}>
<div style={style} className={`${props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!props.showAt ? styles.modalWhiteFixed : ""}`}>
{props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{props.children}
</div>
</div> :
null}
</React.Fragment>
)
}
}