I have this code with which I can check when the bottom
of a div
is reached by scrolling
:
const checkBottomDiv = (el: HTMLElement) => {
return el.getBoundingClientRect().bottom - 400 <= window.innerHeight;
};
const contentArticleId = document.getElementById("myDiv") as HTMLElement;
const trackScrolling = () => {
callback();
if (checkBottomDiv(contentArticleId)) {
console.log("bottomDiv");
document.removeEventListener("scroll", trackScrolling);
}
};
document.addEventListener("scroll", trackScrolling);
I would like to reuse this functionality in other components
and for this reason, I would like to put this logic in a separate function and then call it (function.ts
).
I am doing this:
app.tsx. //component
useEffect(() => {
let element = document.getElementById("myDiv") as HTMLElement;
trackScrolling(element, callback);
})
function.ts. //function file
const checkBottomDiv = (el: HTMLElement) => {
return el.getBoundingClientRect().bottom - 400 <= window.innerHeight;
};
export const trackScrolling = (element: HTMLElement, callback: () => void) => {
if (checkBottomDiv(element)) {
callback();
document.removeEventListener("scroll", trackScrolling);
}
};
document.addEventListener("scroll", trackScrolling);
but I get errors that I don't know how to fix.
this is my live code:
https://codesandbox.io/s/epic-solomon-hu3e3
what am I doing wrong and how can I fix it.
CodePudding user response:
Your document.addEventListener("scroll", trackScrolling);
is not inside of the trackScrolling
function. You'll want to move that inside of the function body so that it has access to the callback
. Your code should look like this:
export const trackScrolling = (element: HTMLElement, callback: () => void) => {
if (checkBottomDiv(element)) {
callback();
document.removeEventListener("scroll", trackScrolling);
}
document.addEventListener("scroll", trackScrolling);
};
Also, when writing custom functionality for React like this, if the logic depends on a hook (like useEffect
), it can be cleaner to include the hook in the custom function as well. For example, you might want something more like this:
app.tsx. //component
useTrackScrolling("myDiv", callback);
function.ts. //function file
const checkBottomDiv = (el: HTMLElement) => {
return el.getBoundingClientRect().bottom - 400 <= window.innerHeight;
};
export const useTrackScrolling = (id: string, callback: () => void) => {
const element = document.getElementById("myDiv") as HTMLElement;
useEffect(() => {
const listener = () => {
if (checkBottomDiv(element)) {
callback();
document.removeEventListener("scroll", listener);
}
}
document.addEventListener("scroll", listener);
return () => document.removeEventListener("scroll", listener);
}, [element, callback]);
};
That's just my opinion though, you can write your code however you prefer :)
CodePudding user response:
Even though you can, you may actually not want to do it this way. A better approach would involve attaching the event listener inside the componentDidMount lifecycle or the useEffect hook. This translates to the following code:
const MyWrapperComponent = (props) => {
useEffect(()=>{
document.addEventListener('scroll', (e)=>{
// do something
});
return ()=>{
document.removeEventListener("scroll");
}
},[]);
}
But since you want to use the scroll event in many components putting this useEffect hook inside all of them will spaghettify your code, so to avoid this, you can make use of the context API to share the event data with all the components that needs it.