как я могу поместить document.addEventListener(«прокрутка») в другой файл, чтобы вызвать его в моем компоненте?

#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. Это означает, что элемент равен нулю, что может произойти либо в том случае, если переданный идентификатор неверен, либо если элемент просто еще не был отображен на странице. Я отредактировал свой ответ, чтобы убедиться, что элемент существует, прежде чем проверять его ограничивающую прямую.