#javascript #reactjs #dom
Вопрос:
У меня есть этот код, с помощью которого я могу проверить, когда bottom
a div
достигается 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);
Я хотел бы повторно использовать эту функциональность в других components
, и по этой причине я хотел бы поместить эту логику в отдельную функцию, а затем вызвать ее ( function.ts
).
Я делаю это:
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);
но я получаю ошибки, которые не знаю, как исправить.
это мой живой код:
https://codesandbox.io/s/epic-solomon-hu3e3
что я делаю не так и как я могу это исправить.
Комментарии:
1. Вам следует рассмотреть возможность использования для этого сервера IntersectionObserver вместо прослушивания событий прокрутки.
Ответ №1:
Даже если вы можете, вы, возможно, на самом деле не захотите делать это таким образом. Лучший подход заключался бы в подключении прослушивателя событий внутри жизненного цикла componentDidMount или крючка useEffect. Это переводится в следующий код:
const MyWrapperComponent = (props) => {
useEffect(()=>{
document.addEventListener('scroll', (e)=>{
// do something
});
return ()=>{
document.removeEventListener("scroll");
}
},[]);
}
Но поскольку вы хотите использовать событие прокрутки во многих компонентах, размещение этого крючка эффекта использования внутри всех из них приведет к спагеттификации вашего кода, поэтому, чтобы избежать этого, вы можете использовать контекстный API для обмена данными о событиях со всеми компонентами, которым это необходимо.
Комментарии:
1. спасибо, но правильна ли эта строка? document.removeEventListener(«прокрутка»);?
Ответ №2:
Ваш document.addEventListener("scroll", trackScrolling);
не находится внутри trackScrolling
функции. Вы захотите переместить его внутрь тела функции, чтобы у него был доступ к callback
. Ваш код должен выглядеть следующим образом:
export const trackScrolling = (element: HTMLElement, callback: () => void) => {
if (element amp;amp; checkBottomDiv(element)) {
callback();
document.removeEventListener("scroll", trackScrolling);
}
document.addEventListener("scroll", trackScrolling);
};
Кроме того, при написании пользовательской функциональности для React, подобной этой, если логика зависит от крючка (например useEffect
), может быть проще включить крючок и в пользовательскую функцию. Например, вам может понадобиться что-то более похожее на это:
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(id) as HTMLElement;
useEffect(() => {
const listener = () => {
if (element amp;amp; checkBottomDiv(element)) {
callback();
document.removeEventListener("scroll", listener);
}
}
document.addEventListener("scroll", listener);
return () => document.removeEventListener("scroll", listener);
}, [element, callback]);
};
Это только мое мнение, хотя вы можете писать свой код так, как вам больше нравится 🙂
Комментарии:
1. Спасибо, но я получаю: Не удается прочитать свойства null (чтение ‘getBoundingClientRect’)
2. Это означает, что элемент равен нулю, что может произойти либо в том случае, если переданный идентификатор неверен, либо если элемент просто еще не был отображен на странице. Я отредактировал свой ответ, чтобы убедиться, что элемент существует, прежде чем проверять его ограничивающую прямую.