React get if element scrolled to the right - reactjs

I have an overflow: scroll div, and I'd like to check if it is scrolled to the right. How can I get an event listener for scroll in React and how can I calculate if it's scrolled to the right horisontally?

const elem = () => {
const [isScrolledRight, setIsScrolledRight] = useState(false)
const handleScroll = (elem: any) => {
const scrollLeft = elem.target.scrollLeft
const scrollWidth = elem.target.scrollWidth
const clientWidth = elem.target.clientWidth
setIsScrolledRight(scrollLeft + clientWidth == scrollWidth)
}
// use isScrolledRight anywhere you need
return (
<div onScroll={handleScroll.bind(this)} /> // this should be horisontally scrollable
)
}

Related

Is there a way to access an iframe scroll position in React?

I tried with useRef, but i'm not receiving anything. Is there something wrong with my code or is it simply not possible to access an iframe scroll?
const iframeRef = useRef(null);
const onScroll = (e) =\> {
if (e?.target) {
const { scrollTop, scrollHeight, clientHeight } = e.target;
if ((scrollTop + clientHeight) / scrollHeight \> 1) {
// TO SOMETHING HERE
console.log('Reached bottom');
}
}
};
<iframe
ref={iframeRef}
src={document.path}
onScroll={onScroll}
/>

Reactjs virtualization infinit scroll

I'm trying to implement a virtualisation component with reactjs.
In order to fill the empty top and bottom gap I used an empty div with dynamic height which depends on the scroll position.
<div style={{ height: topPlaceholderHeight }} />
{visibleItems.map(renderItem)}
<div style={{ height: bottomPlaceholderHeight }} />
When the user scrolls > a scroll event is triggered > placeholderHeight is updated > triggers an other scroll event => infinite loop that leads to an auto scroll to the bottom
const [start, setStart] = useState(0);
const [end, setEnd] = useState(0);
const [scrollTop, setScrollTop] = useState(0);
const parentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const listElement = parentRef.current;
if (!listElement) return;
const itemsPerPage = Math.ceil(listElement.offsetHeight / itemHeight) + 2;
const newStart = Math.max(0, Math.floor(scrollTop / itemHeight) - 1);
const newEnd = Math.min(items.length, newStart + itemsPerPage);
setStart(newStart);
setEnd(newEnd);
}, [items, itemHeight, scrollTop]);
useEffect(() => {
const listElement = parentRef.current;
if (!listElement) return;
const scrollHandler = () => {
setScrollTop(listElement.scrollTop);
};
listElement.addEventListener("scroll", scrollHandler);
return () => listElement.removeEventListener("scroll", scrollHandler);
}, [parentRef]);
Code sandbox
Any suggestions for solving this problem ?

Framer-motion Animation With Typescript: ScrollY doesn't find .current

I'm trying to create an animation that hides the menu when the user scrolls down and when the user returns to the top the menu appears.
Everything works, but the problem comes when I try to give to the scrollY property that gives the useScroll hook a type.
This is the code that I could not find the way to implement the type.
const { scrollY } = useScroll();
const [isScrolling, setScrolling] = useState<boolean>(false);
const handleScroll = () => {
if (scrollY?.current < scrollY?.prev) setScrolling(false);
if (scrollY?.current > 100 && scrollY?.current > scrollY?.prev) setScrolling(true);
};
useEffect(() => {
return scrollY.onChange(() => handleScroll());
});
I found the solution!
Reading the documentation framer, I saw that they updated the way to get the value of the previous and current scroll.
scrollY.get() -> Current
scrollY.getPrevious() -> Previous
const { scrollY } = useScroll();
const [isScrolling, setScrolling] = useState<boolean>(false);
const handleScroll = () => {
if (scrollY.get() < scrollY.getPrevious()) setScrolling(false);
if (scrollY.get() > 100 && scrollY.get() > scrollY.getPrevious()) setScrolling(true);
};
useEffect(() => {
return scrollY.onChange(() => handleScroll());
});

Problem with detecting scroll position in react

I'm making a effect similar to FullPage.js (like scroll-snap css)
For that, I defined a state for scroll position
and when scrolling down, I made it move to component automatically
using window.scrollTo.
const Page = () => {
const [pos, setPos] = useState(0);
const target = useRef();
const [snap,setSnap] = useState(false);
const onScroll = () => {
setPos(window.scrollY);
};
useEffect(() => {
window.addEventListener('scroll',onScroll);
return () => {
window.removeEventListener("scroll",onScroll);
}
},[]);
...
if (snap) { // if snap turns true then move to component
target.current.scrollIntoView({behavior:'smooth'})
}
return (
<div>
<Component ref={traget}>
..
</Component>
</div>
)
}
export default Page
This code works. But it moves too slowly.
I think defining a state for scroll position
call re-render. might not be that..
Could you tell me how can I solve this?

setState hook not updating

I have a header that I want to hide on scroll down and show on scroll up.
To do that, I saved the scrolling position as prevScrollPos in the state to compare it to the current scrolling position onscroll, and then update prevScrollPos to the current:
const [visible, setVisible] = React.useState(true);
const [prevScrollPos, setPrevScrollPos] = React.useState(window.pageYOffset);
const handleScroll = () => {
const scrollPos = window.pageYOffset;
const visible = scrollPos < prevScrollPos;
setVisible(visible);
setPrevScrollPos(scrollPos);
}
The problem is that, for some reason PrevScrollPos doesn't get updated.
Pen: https://codepen.io/moaaz_bs/pen/jgGRoj?editors=0110
You need to modify your useEffect function:
React.useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
});
Basically you don't have access to prevScrollPos in your handler, therefore prevScrollPos inside the listener will always return 0. To solve this, the dependency array should not be present.
-> + Do not forget to remove the event listener after adding it. :-)
Can you try this:
const [visible, setVisible] = React.useState(true);
const [prevScrollPos, setPrevScrollPos] = React.useState(window.pageYOffset);
const handleScroll = () => {
const scrollPos = window.pageYOffset;
const visible_new = scrollPos < prevScrollPos;
setVisible(visible_new);
setPrevScrollPos(scrollPos);
}

Resources