I\'m building a form - series of questions (radio buttons) the user needs to answer before he can move on to the next screen. For fields validation I\'m using yup (npm packa
Based on Avraam's answer I wrote a Typescript-compatible small hook to satisfy the actual React code convention.
import { createRef, useEffect, useState } from "react";
import throttle from "lodash.throttle";
/**
* Check if an element is in viewport
* @param {number} offset - Number of pixels up to the observable element from the top
* @param {number} throttleMilliseconds - Throttle observable listener, in ms
*/
export default function useVisibility(
offset = 0,
throttleMilliseconds = 100
): [Boolean, React.RefObject] {
const [isVisible, setIsVisible] = useState(false);
const currentElement = createRef();
const onScroll = throttle(() => {
if (!currentElement.current) {
setIsVisible(false);
return;
}
const top = currentElement.current.getBoundingClientRect().top;
setIsVisible(top + offset >= 0 && top - offset <= window.innerHeight);
}, throttleMilliseconds);
useEffect(() => {
document.addEventListener('scroll', onScroll, true);
return () => document.removeEventListener('scroll', onScroll, true);
});
return [isVisible, currentElement];
}
Usage example:
const Example: FC = () => {
const [ isVisible, currentElement ] = useVisibility(100);
return ;
};
You can find the example on Codesandbox. I hope you will find it helpful!