具有无限调用依赖项的 useEffect

useEffect with dependency called infinitely

我有一个警报,我想在列表中的项目 added/removed 后隐藏在超时函数中。

useEffect 没有清理超时函数,而是以循环结束。

function App() {
  const [item, setItem] = useState({
    id: "",
    name: "",
  });
  const [list, setList] = useState([]);
  const [isEditing, setISEditing] = useState(false);
  const [alert, setAlert] = useState({
    active: false,
    type: "",
  });

  const addToList = (e) => {
    e.preventDefault();
    setAlert({ active: true, type: "success" });
    let newItem = { id: new Date().getTime().toString(), name: item };
    e.preventDefault();
    setList([...list, newItem]);
  };

  const removeFromList = (id) => {
    setAlert({ active: true, type: "danger" });
    setList(list.filter((item) => item.id !== id));
  };

  useEffect(() => {
   const timeout = setTimeout(() => {
      setAlert({ active: false, type: "" });
    }, 3000);
    return () => clearTimeout(timeout);
  }, [alert.active]);

我在下面有一个类似的例子,但是 useEffect 并没有以循环结束,尽管我改变了 useEffect 中的状态。 两者到底有什么区别?

const SingleColor = ({ rgb, weight, index }) => {
  const [alert, setAlert] = useState(false);
  const hex = rgbToHex(...rgb);

 useEffect(() => {
    const timeout = setTimeout(() => {
      setAlert(false);
    }, 3000);
    return () => clearTimeout(timeout);
  }, [alert]);

  return (
    <article
      className={`color ${index > 10 && "color-light"}`}
      style={{ backgroundColor: hex }}
      onClick={() => {
        setAlert(true);
        navigator.clipboard.writeText(hex);
      }}
    >
      <p className="percent-value">{weight}%</p>
      <p className="color-value">{hex}</p>
      {alert && <p className="alert">Copied to clipboard!</p>}
    </article>
  );
};

export default SingleColor;

使用 alert.active 依赖项,您要在每次 alert.active 更改时重新触发 useEffect。在 useEffect 中,您正在为 alert.active 设置一个新值,因此创建了一个无限循环。

您应该直接在 addToList 或 remove from list 函数的末尾调用超时。如果你愿意,你可以将它隔离在一个单独的函数中

const cancelTimeout = () => {
   setTimeout(() => setAlert({ active: false, type: "" }), 3000)
}

并在 AddToListremoveFromList

的末尾调用 cancelTimeout