柚子青年。

React Hooks 移除 addEventListener 监听
柚子青年。
2022-09-27

起因

当我在 Hooks 内使用 addEventListener 监听 scroll 事件时,然后使用 removeEventListener 移除监听发现移除失效。

const scroll = () => {
    useEffect(() => {
        document.addEventListener("scroll", scrollCallback);
    }, []);

    const scrollCallback = (e) => {
        console.log(e)
    }

    const clearScroll = () => {
        document.removeEventListener("scroll", scrollCallback);
    }

    return <button onClick={clearScroll}>Clean</button>;
}

这是一个在初始化完成后会在 document 添加一个 scroll 事件监听,点击按钮之后会清除监听事件。

但是事实上并不会按照预想的方式执行,在点击按钮之后并不会清除 scroll 事件;

每一次渲染都有它自己的事件处理函数

Hooks 每次渲染的时候事件都是自己的内部重新定义的,所以 removeEventListener 在移除的时候判定到的 scrollCallback 不是同一个回调函数, 这里有更详细的介绍。

useCallback

const memoizedCallback = useCallback(
    () => {
        doSomething(a, b);
    },
    [a, b],
);

把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。这里有更详细的介绍。

改造

const scroll = () => {
    const eventListener = useCallback((e) => scrollCallback(e), []);

    useEffect(() => {
        document.addEventListener("scroll", eventListener);
    }, []);

    const scrollCallback = (e) => {
        console.log(e)
    }

    const clearScroll = () => {
        document.removeEventListener("scroll", eventListener);
    }

    return <button onClick={clearScroll}>Clean</button>;
}