Wie kann man effektiv damit umgehen, dass useEffect in React zweimal ausgeführt wird?
P粉759457420
P粉759457420 2023-10-20 00:00:23
0
2
798

Ich habe einen Zähler und useEffect 中的 console.log() 来记录我的状态中的每个更改,但是 useEffect wird beim Montieren zweimal aufgerufen. Ich verwende React 18. Hier ist die CodeSandbox für mein Projekt und der Code unten:

import  { useState, useEffect } from "react";

const Counter = () => {
  const [count, setCount] = useState(5);

  useEffect(() => {
    console.log("rendered", count);
  }, [count]);

  return (
    <div>
      <h1> Counter </h1>
      <div> {count} </div>
      <button onClick={() => setCount(count + 1)}> click to increase </button>
    </div>
  );
};

export default Counter;

P粉759457420
P粉759457420

Antworte allen(2)
P粉156532706

更新:回顾一下这篇文章,稍微明智一点,请不要这样做。

使用ref或创建一个没有的自定义hook

export const useClassicEffect = createClassicEffectHook();

function createClassicEffectHook() {
  if (import.meta.env.PROD) return React.useEffect;

  return (effect: React.EffectCallback, deps?: React.DependencyList) => {
    React.useEffect(() => {
      let isMounted = true;
      let unmount: void | (() => void);

      queueMicrotask(() => {
        if (isMounted) unmount = effect();
      });

      return () => {
        isMounted = false;
        unmount?.();
      };
    }, deps);
  };
}
P粉459440991

自 React 18 起,当您使用 StrictMode 进行开发时,

useEffect 在挂载时被调用两次是正常的。以下是他们在 文档

这看起来很奇怪,但最终,我们通过缓存 HTTP 请求并在有两个调用时使用清理函数来编写更好的 React 代码,无错误,符合当前指南,并与未来版本兼容一个问题。这是一个例子:

/* Having a setInterval inside an useEffect: */

import { useEffect, useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => setCount((count) => count + 1), 1000);

    /* 
       Make sure I clear the interval when the component is unmounted,
       otherwise, I get weird behavior with StrictMode, 
       helps prevent memory leak issues.
    */
    return () => clearInterval(id);
  }, []);

  return 
{count}
; }; export default Counter;

在这篇非常详细的文章中,React 团队解释了 useEffect 前所未有并举例说明:

对于您的特定用例,您可以保持原样,无需担心。并且您不应该尝试将这些技术与 useEffect 中的 useRefif 语句一起使用以使其触发一次,或删除 StrictMode ,因为正如您可以在 文档

/* As a second example, an API call inside an useEffect with fetch: */

useEffect(() => {
  const abortController = new AbortController();

  const fetchUser = async () => {
    try {
      const res = await fetch("/api/user/", {
        signal: abortController.signal,
      });
      const data = await res.json();
    } catch (error) {
      // ℹ️: The error name is "CanceledError" for Axios.
      if (error.name !== "AbortError") {
        /* Logic for non-aborted error handling goes here. */
      }
    }
  };

  fetchUser();

  /* 
    Abort the request as it isn't needed anymore, the component being 
    unmounted. It helps avoid, among other things, the well-known "can't
    perform a React state update on an unmounted component" warning.
  */
  return () => abortController.abort();
}, []);
function TodoList() {
  const todos = useSomeDataFetchingLibraryWithCache(`/api/user/${userId}/todos`);
  // ...

如果您仍然遇到问题,也许您正在使用 useEffect ,正如他们在 不是效果:初始化应用程序 不是效果:购买产品,我建议您阅读文章作为一个整体。

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage