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