useEffect не удаляет мои слушатели событий - PullRequest
2 голосов
/ 04 февраля 2020

У меня есть пользовательский хук, который устанавливает несколько прослушивателей событий, которые работают как задумано. Но я заметил, что мои слушатели событий не удаляются при повторной визуализации. Что я делаю не так (слушатели событий в последней части кода)? Т.е. я заметил это на событиях тега привязки; handleLink.

export default function useCursorSelector(
  selectorRef: React.RefObject<HTMLElement>,
  onClickLink: (url: string) => void,
  onSelect: (text: string) => void
) {
  const classes = useStyles();

  const handleSelection = React.useCallback(
    (event: MouseEvent) => {
      const selection: Selection | null = window.getSelection();
      if (selection) {
        const text = fullStringSelection(selection);
        selection.removeAllRanges();
        onSelect(text);
      }
      event.stopPropagation();
    },
    [onSelect]
  );

  const handleLink = React.useCallback(
    (a: HTMLAnchorElement) => (e: MouseEvent) => {
      e.preventDefault();
      onClickLink(a.href);
    },
    [onClickLink]
  );

  React.useEffect(() => {
    if (selectorRef.current) {
      wrapInSpans(selectorRef.current, classes.highlight, onClickLink);
    }
  }, [classes.highlight, selectorRef, onClickLink]);

  React.useEffect(() => {
    selectorRef!
      .current!.querySelectorAll(`.${classes.highlight}`)
      .forEach((e: any) => {
        e.addEventListener("mouseup", handleSelection);
      });
    selectorRef!
      .current!.querySelectorAll(`a`)
      .forEach((a: HTMLAnchorElement) => {
        a.addEventListener("click", handleLink(a));
      });
    return () => {
      selectorRef!
        .current!.querySelectorAll(`.${classes.highlight}`)
        .forEach((e: any) => {
          e.removeEventListener("mouseup", handleSelection);
        });
      selectorRef!
        .current!.querySelectorAll(`a`)
        .forEach((a: HTMLAnchorElement) => {
          a.removeEventListener("click", handleLink(a));
        });
    };
  }, [handleSelection, handleLink, classes.highlight, selectorRef]);
}

1 Ответ

2 голосов
/ 04 февраля 2020

Каждый раз, когда вы вызываете handleLink(a), вы создаете новую анонимную функцию для использования в качестве обратного вызова для вашего обработчика событий.

Когда вы вызываете removeEventListener, вы должны передавать ссылку на тот же обратный вызов, который вы использовали для прикрепления события, однако каждый раз, когда вы вызываете handleLink, вы создаете новую анонимную функцию.

Вы можете каким-то образом сохранить ссылку на созданные вами обратные вызовы или переписать handleLink, чтобы вам вообще не нужно было передавать элемент.

const handleLink = React.useCallback((e: MouseEvent) => {
    e.preventDefault();
    onClickLink(e.currentTarget.href);
}, [onClickLink]);

...

React.useEffect(() => {
  selectorRef!
    .current!.querySelectorAll(`.${classes.highlight}`)
    .forEach((e: any) => {
      e.addEventListener("mouseup", handleSelection);
    });
  selectorRef!
    .current!.querySelectorAll(`a`)
    .forEach((a: HTMLAnchorElement) => {
      a.addEventListener("click", handleLink);
    });
  return () => {
    selectorRef!
      .current!.querySelectorAll(`.${classes.highlight}`)
      .forEach((e: any) => {
        e.removeEventListener("mouseup", handleSelection);
      });
    selectorRef!
      .current!.querySelectorAll(`a`)
      .forEach((a: HTMLAnchorElement) => {
        a.removeEventListener("click", handleLink);
      });
  };
}, [handleSelection, handleLink, classes.highlight, selectorRef]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...