React Hooks removeEventListener 使用无效问题

时间:2025-02-28 07:34:53

组件卸载时

和原来的componentWillUnmount一样的用法, 在useEffect return里调用就可以了

 useEffect(() => {
    window.addEventListener('click', clickFunc);
    return () => {
      window.removeEventListener('click', clickFunc);
    };
  });

组件使用过程中

当组件不涉及重新渲染时了, 像这么写完全没问题, 点击Remove Click to Console之后监听取消.

import React, { useState } from "react";

  const App = () => {
    // const [state, setState] = useState(0)

    const handleAddListening = () => {
      window.addEventListener('click', clickFunc)
      // setState(state + 1)
    }

    const clickFunc = () => {
      console.log('clicking')
    }

    const handleRemoveListening = () => {
      window.removeEventListener('click', clickFunc)
    }

    return (
      <div className="App">
        <div onClick={handleAddListening}>
          Click to Console
        </div>
        <div onClick={handleRemoveListening}>
          Remove Click to Console
        </div>
      </div>
  );
}

现在我们把以上代码中的注释取消掉, 加入useState导致组件再次渲染, 此时发现无论如何点击Remove Click to Console, 点击事件发生时, 会一直console clicking.
甚至再次单击Click to Console触发绑定事件, 发现会同时console clicking两次;
再再次单击, console次数会继续累计增加.

这是因为每次触发组件再次渲染, clickFunc作为组件内的方法, 会跟着一同再次渲染, 并且在内存里, 再次渲染出的 clickFunc !== 前clickFunc.
所以removeEventListener无法解除绑定, 再次addEventListener则会绑定一个新方法.

解决方案:

const clickFunc = useCallback(() => {
    console.log("clicking");
  }, []);

使用无依赖的useCallback解决clickFunc的重新渲染问题