I wanted to disable the scrollbar when a popup screen is opened and with my current method, the screen tends to randomly glitch on scroll despite the scrollbar being disabled. So, is there a better way to create a scrollbar handler component
My Current Method
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
export const scrollbarDisable = () => {
window.onscroll = () => {
window.scrollTo(scrollLeft, scrollTop);
};
};
export const scrollbarEnable = () => {
window.onscroll = () => {};
};
Could you do something like this? When you open the modal/popup you could set the body overflow to true or not.
useEffect(() => {
document.body.style.overflow = 'unset';
if (popupOpen) {
document.body.style.overflow = 'hidden';
}
}, [popupOpen]);
May react-remove-scroll-bar be usefull.
Related
I'm using the infinite scrolling for my react app and have this function that detects when I'm exactly at the bottom of the page:
const [isFetching, setIsFetching] = useState(false);
// Fire Upon Reaching the Bottom of the Page
const handleScroll = () => {
if (
window.innerHeight +
Math.max(
window.pageYOffset,
document.documentElement.scrollTop,
document.body.scrollTop
) !==
document.documentElement.offsetHeight
)
return;
setIsFetching(true);
};
// Debounce the Scroll Event Function and Cancel it When Called
const debounceHandleScroll = debounce(handleScroll, 100);
useEffect(() => {
window.addEventListener("scroll", debounceHandleScroll);
return () => window.removeEventListener("scroll", debounceHandleScroll);
}, [debounceHandleScroll]);
debounceHandleScroll.cancel();
The problem lies when I load my page in my phone and it seems that because of the tab or bar of the mobile browser, it's not detecting the bottom of the page and so the content doesn't load.
Is there any way I can detect that the user is near the bottom and fire that function only then?
I think an IntersectionObserver could be what you're looking for.
You can check this tutorial for for basic information: https://dev.to/producthackers/intersection-observer-using-react-49ko
You could also turn this into a custom hook which takes a ref (in your case, a n element at the bottom of you page):
import { useEffect, useState } from 'react';
const useIsVisible = ref => {
const [isIntersecting, setIntersecting] = useState(false);
const observer = new IntersectionObserver(([entry]) =>
setIntersecting(entry.isIntersecting),
);
useEffect(() => {
observer.observe(ref.current);
return () => {
observer.disconnect();
};
}, []);
return isIntersecting;
};
export default useIsVisible;
Maybe also the following package might help you, it makes implementing infinity scroll quite easy:
https://www.npmjs.com/package/react-infinite-scroll-component
I managed to changed the scroll function into this and now it's working.
const handleScroll = () => {
if (
window.innerHeight +
Math.max(
window.pageYOffset,
document.documentElement.scrollTop,
document.body.scrollTop
) >
document.documentElement.offsetHeight - 100
) {
setIsFetching(true);
} else {
return;
}
};
The number that's being reduced from document.documentElement.offsetHeight determines the amount remaining from the bottom of the page. 100 seems enough for me since I tested it on my phone and it works.
I am trying to select some value preferably px of how much I have scrolled down so I can conditionally hide the element.
Something like total height - scrolled height would be ideal
Problem
I'm having trouble selecting the proper property.
console.log doesn't help as it renders the actual body tag then.
Here's the code
const scrollHandler = (event) => {
let scrollTop = event.srcElement.body.offsetHeight;
console.log(scrollTop)
setIsSearchVisible(false)
}
useEffect(() => {
window.addEventListener('scroll', scrollHandler, true);
return () => {
window.removeEventListener('scroll', scrollHandler, true);
}
},[])
Would also appreciate it if someone could point me to the documentation of the same thanks!
I was able to figure it out , Instead of using the event object I simply used the window object, Something like this
const scrollHandler = (event) => {
let scrollTop = window.scrollY;
console.log(scrollTop);
setIsSearchVisible(false);
};
useEffect(() => {
window.addEventListener("scroll", scrollHandler, true);
return () => {
window.removeEventListener("scroll", scrollHandler, true);
};
}, []);
I created a responsive sidebar, the logic is implemented as follows, when the screen reaches below 765 pixels the sidebar is automatically hidden, but the problem is that when I refresh the page which is below 765 pixels the sidebar is displayed it looks like this
My code looks like this
function SideBar(props) {
const {someValue} = useContext(SideBarContext);
const {SideBarValue, SideBarWallpaperValue} = React.useContext(CounterContext);
const [SideBarThemeValue] = SideBarValue;
const [SideBarBackgroundValue] = SideBarWallpaperValue;
const [sideBarOpen, setSideBarOpen] = useState(true);
const [SideBarButtonContainer, setSideBarButtonContainer] = useState(false);
useEffect(() => {
window.addEventListener("resize", resize);
})
const resize = () => {
if(window.innerWidth < 765) {
setSideBarOpen(false)
setSideBarButtonContainer(true)
} else {
setSideBarOpen(true)
setSideBarButtonContainer(false)
}
}
const showSideBar = () => {
setSideBarOpen(!sideBarOpen)
}
return (
<>
{
SideBarButtonContainer ? <div className={"showSideBarButtonContainer"}>
<img className={"showSideBarButton"} onClick={() => showSideBar()} src={SideBarMenuIcon} alt={"Open"} />
</div> : null
}
<Menu isOpen={sideBarOpen}>
</Menu>
</>
);
}
I assume that when I refresh the page the sideBarOpen value becomes true, although I did a check inside the resize method and notice when I start to shrink the screen the sidebar disappears it looks like this
Try using useLayoutEffect to do push some state changes before actually rendering to screen.
useLayoutEffect(() => {
if (window.innerWidth < 765) {
setSideBarOpen(false);
setSideBarButtonContainer(true);
}
window.addEventListener("resize", resize);
}, [])
The default state of your sidebar is open, however you must calculate the initial state based on the width. Also you must only initialise the listener on window resize on initial render.
const [sideBarOpen, setSideBarOpen] = useState(() => window.innerWidth > 765);
const [SideBarButtonContainer, setSideBarButtonContainer] = useState(() => window.innerWidth < 765);
useEffect(() => {
window.addEventListener("resize", resize);
}, []); // Only initialize listener on initial render
const resize = () => {
if(window.innerWidth < 765) {
setSideBarOpen(false)
setSideBarButtonContainer(true)
} else {
setSideBarOpen(true)
setSideBarButtonContainer(false)
}
}
I wanna add event listener when user scrolling in my web app, but not working
componentDidMount = () => {
let scrollPosition = window.scrollY;
let header = document.getElementById("topBar");
window.addEventListener('scroll', () => {
scrollPosition = window.scrollY;
console.log(scrollPosition)
});
}
can you guys help me to solve this problem ?
try this instead:
componentDidMount() {
let header = document.getElementById("topBar");
window.addEventListener('scroll', this.scrollFunction}
}
scrollFunction = () => {
console.log(window.scrollY)
}
I am trying to figure out how to implement window.addEventListener in React. I'm developing a website with Gatsby and in "development" environment it works but whenever I start in production it gets an error. This is my code:
const checkHeader = () => {
// Detect scroll position
let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
if (viewportWidth > 1100) {
let scrollPosition = Math.round(window.scrollY);
if (scrollPosition > 100){
document.querySelector('#nav').classList.add(`${headerStyles.sticky}`);
}
else {
document.querySelector('#nav').classList.remove(`${headerStyles.sticky}`);
}
} else {
}
};
// Run the checkHeader function every time you scroll
window.addEventListener('scroll', checkHeader);
I want to apply a class when Scroll. I've checked that I can't use "window." in React. How is the way to implement this code in React?
During development, react components are only run in the browser where window is defined. When building, Gatsby renders these components on the server where window is not defined.
Generally with React, the solution is to only access window in componentDidMount or to check that window exists before accessing it.
const checkHeader = () => {
// Detect scroll position
let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
if (viewportWidth > 1100) {
let scrollPosition = Math.round(window.scrollY);
if (scrollPosition > 100){
document.querySelector('#nav').classList.add(`${headerStyles.sticky}`);
}
else {
document.querySelector('#nav').classList.remove(`${headerStyles.sticky}`);
}
} else {
}
};
// Check that window exists before accessing it
if (typeof window !== 'undefined') {
// Run the checkHeader function every time you scroll
window.addEventListener('scroll', checkHeader);
}
You can directly add window events with Gatsby since it performs server side rendering. To do that you need to add you listeners in gatsby-browser.js inside onClientEntry method which is called when client is loaded
// gatsby-browser.js
// ES6
const checkHeader = () => {
// Detect scroll position
let viewportWidth = window.innerWidth || document.documentElement.clientWidth;
if (viewportWidth > 1100) {
let scrollPosition = Math.round(window.scrollY);
if (scrollPosition > 100){
document.querySelector('#nav').classList.add(`${headerStyles.sticky}`);
}
else {
document.querySelector('#nav').classList.remove(`${headerStyles.sticky}`);
}
} else {
}
};
export const onClientEntry = () => {
// Run the checkHeader function every time you scroll
window.addEventListener('scroll', checkHeader);
}
Calling the function on did mount of the root component might solve your issue. for example:
// your entry component
const App = () => {
React.useEffect(() => { // Will be called after mounting the componnent.
onClientEntry();
}, []);
return (
<Home />
);
}
Hope this helps