首页 > 解决方案 > React useEffect 缺少依赖错误,但它在那里

问题描述

我有这个组件,我正在使用 useRef 和 useEffect 来处理弹出窗口外的点击,以便我可以关闭它。

我添加了 useEffect 需要的两个依赖项,但出现此错误:

The 'handleClickOutside' function makes the dependencies of useEffect Hook (at line 117) change on every render. Move it inside the useEffect callback. Alternatively, wrap the 'handleClickOutside' definition into its own useCallback()

正如您在此处看到的,我添加了两个依赖项,但它仍然会引发此错误/警告:

  useEffect(() => {
    if (isOverlayOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    } else {
      document.removeEventListener("mousedown", handleClickOutside);
    }
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOverlayOpen, handleClickOutside]);

任何想法如何解决这一问题?

这里是代码框: https ://codesandbox.io/s/laughing-newton-1gcme ?fontsize=14&hidenavigation=1&theme=dark 问题出在 src/components/typeahead 第 100 行

这里是组件代码:

function ResultsOverlay({
  isOpen,
  items,
  selectItem,
  highlightedOption,
  setIsOverlayOpen,
  isOverlayOpen
}) {
  const node = useRef();
  const handleClickOutside = e => {
    if (node.current.contains(e.target)) {
      return;
    }
    setIsOverlayOpen(false);
  };

  useEffect(() => {
    if (isOverlayOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    } else {
      document.removeEventListener("mousedown", handleClickOutside);
    }
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOverlayOpen]);

  function matchedOptionsClass(index) {
    if (highlightedOption === index) {
      return "ph4 list f3 sesame-red list-item pointer";
    }
    return "ph4 list sesame-blue list-item pointer";
  }

  if (isOpen) {
    return (
      <div className="absolute" ref={node}>
        <ul className="w5 mt0 pa0 h5 overflow-scroll shadow-5 dib">
          {items &&
            items.map((item, index) => (
              <li
                onClick={() => selectItem(item)}
                className={matchedOptionsClass(index)}
              >
                {item}
              </li>
            ))}
        </ul>
      </div>
    );
  } else {
    return null;
  }
}

标签: reactjsreact-hooks

解决方案


两个问题:

首先,做 linst 告诉你的事情,把你的函数定义移动到你的效果中

  useEffect(() => {
      const handleClickOutside = e => {
          if (node.current.contains(e.target)) {
              return;
          }
          setIsOverlayOpen(false);
       };
    if (isOverlayOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    } else {
      document.removeEventListener("mousedown", handleClickOutside);
    }
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOverlayOpen]);

其次,setIsOverlayOpen是通过 提供的回调props,因此它没有稳定的签名并在每次渲染时触发效果。

假设这setIsOverlayOpen是一个 setteruseState并且不需要更改它的签名,您可以通过使用将处理程序包装在附加的依赖检查层中来解决此问题useCallback

  const stableHandler = useCallback(setIsOverlayOpen, [])      

  useEffect(() => {
      const handleClickOutside = e => {
          if (node.current.contains(e.target)) {
              return;
          }
          stableHandler(false);
       };
    if (isOverlayOpen) {
      document.addEventListener("mousedown", handleClickOutside);
    } else {
      document.removeEventListener("mousedown", handleClickOutside);
    }
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [isOverlayOpen, stableHandler]);

推荐阅读