useEffect不会删除我的事件侦听器

时间:2020-02-04 20:04:23

标签: javascript reactjs react-hooks

我有一个自定义钩子,该钩子设置了多个按预期工作的事件侦听器。但是我注意到,事件监听器在重新渲染时不会被删除。我做错了什么(代码后半部分的事件监听器)?即我已经在锚标记事件中注意到它; 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 个答案:

答案 0 :(得分:2)

每次调用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]);