反应18严格的模式,导致组件渲染两次

发布于 2025-02-04 07:05:54 字数 1328 浏览 5 评论 0 原文

React版本18 中严格模式的更改导致我的代码渲染两次,这会导致 Axios 中止控制器的错误,但我不知道如何清除错误在应用程序呈现两次之后的浏览器控制台。

请注意:我正在研究注册 /登录应用程序,即使我成功登录后, react < / strong>将我带回登录页面,因为 axios < /strong>错误

useEffect(() => {
    let isMounted = true;
    // used by axios to cancel request
    const controller = new AbortController();

    const getGoals = async () => {
        try {
            const response = await goalPrivate.get("/goals", {
                // option to cancel request
                signal: controller.signal
            })
            console.log(response?.data);
            // set goals state when component mounts
            isMounted && setGoals(response?.data);
        } catch (error) {
            console.log(error.message);
            // when refreshToken expires
            navigate("/login", { state: { from: location }, replace: true });
        }
    }

    getGoals();

    // cleanup function
    return () => {
        // don't set state if component unmounts
        isMounted = false;
        // cancel request if component unmounts
        controller.abort();
    }
    
    // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

The changes to strict-mode in React version 18 causes my code to render twice, which causes an error in axios abort controller, but I don't know how to clear the error from the browser console after the app renders twice.

Please note: I am working on a sign-up / log-in app and even after I successfully logged in, React takes me back to the log-in page, because of the axios error

useEffect(() => {
    let isMounted = true;
    // used by axios to cancel request
    const controller = new AbortController();

    const getGoals = async () => {
        try {
            const response = await goalPrivate.get("/goals", {
                // option to cancel request
                signal: controller.signal
            })
            console.log(response?.data);
            // set goals state when component mounts
            isMounted && setGoals(response?.data);
        } catch (error) {
            console.log(error.message);
            // when refreshToken expires
            navigate("/login", { state: { from: location }, replace: true });
        }
    }

    getGoals();

    // cleanup function
    return () => {
        // don't set state if component unmounts
        isMounted = false;
        // cancel request if component unmounts
        controller.abort();
    }
    
    // eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

终难愈 2025-02-11 07:05:54

React strictMode调用所有效果的所有效果两次,以确保其清理/卸载处理程序按预期工作。即使他们有空的依赖列表,并且通常不会在网站关闭之前卸载,您可能需要相应地更改效果。

请注意,这仅发生在严格 +开发模式下。在生产构建中,效果只会在其依赖性变化时一次调用。

前上下文,请参见 https://reactjs.s.s.org/strict-ocs/strict-coms/strict-com- mode.html#确保可调用状态

React StrictMode calls all Effects twice to make sure their cleanup/unmount handlers work as intended. You may need to change your effects accordingly, even if they have an empty dependency list and would normally not unmount before the site is closed.

Note, this only happens in Strict + development mode. In a production build, effects will only be called once and when their dependencies change.

Fore more context, see https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state

惜醉颜 2025-02-11 07:05:54

有相同的问题并以这种方式修复。

当中止流行程序中流产时,您会跳到捕获量,因此您只需检查信号是否流产或不执行代码的其余部分即可。

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

    fetch("https://pokeapi.co/api/v2/pokemon", {
      signal: abortController.signal,
    })
      .then((res) => res.json())
      .then(console.log)
      .catch((err) => {
        if (abortController.signal.aborted) return;
        console.log(err);
        // Your navigate
      });

    return () => {
      abortController.abort();
    };
  }, []);

Had the same problem and fixed it this way.

When the abortController is aborted you jump to the catch so you just check if the signal is aborted or not to execute the rest of your code.

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

    fetch("https://pokeapi.co/api/v2/pokemon", {
      signal: abortController.signal,
    })
      .then((res) => res.json())
      .then(console.log)
      .catch((err) => {
        if (abortController.signal.aborted) return;
        console.log(err);
        // Your navigate
      });

    return () => {
      abortController.abort();
    };
  }, []);
中性美 2025-02-11 07:05:54

React 18现在具有 strict.mode ,可以安装,卸载和重新安装组件,这会导致 abortController 在第一个删除上发出错误。请记住,只有在index.js中应用strict.mode时,才会在开发模式下发生。在开发模式中,我们可以检查该行为。

try {
     // fetch API data
  } catch (error) {
       if (process.env.NODE_ENV === "development" && error) {
         // ignore the error
        console.log(error.message);
   } else {
     // when refreshToken expires, go back to login
    navigate("/login", { state: { from: location }, replace: true });
  }
}

React 18 now has Strict.Mode which can mount, unmount, and remount components which causes the abortController to issue an error on the first unmount. Remember, this only happens in development mode when Strict.Mode is applied in your index.js. We can check for that behaviour while in development-mode.

try {
     // fetch API data
  } catch (error) {
       if (process.env.NODE_ENV === "development" && error) {
         // ignore the error
        console.log(error.message);
   } else {
     // when refreshToken expires, go back to login
    navigate("/login", { state: { from: location }, replace: true });
  }
}
风吹雪碎 2025-02-11 07:05:54

如果您启用了严格模式,它将在开发模式上发射两倍的使用效果,以确保您知道可能出现的副作用。

If you have the StrictMode enabled, it will fire two times the useEffect on development mode to make sure that you are aware of the possible side-effects that could appear.

暮色兮凉城 2025-02-11 07:05:54

您应该对错误响应进行分类,取决于错误代码或HTTP状态代码。

例如:

...
try {
    // Create axios request
} catch (e: AxiosError) {
    if (error.code === 'ERR_CANCELED') {
        // When abort controller executed
    } else (error.response.status == 401) {
        // When you get http code 401 (Un-authenticated)
        // Eg:
        navigate("/login", { state: { from: location }, replace: true });
    } else {
        // Etc...
    }
}
...

You should classify the error response depends on error code or http status code.

Eg:

...
try {
    // Create axios request
} catch (e: AxiosError) {
    if (error.code === 'ERR_CANCELED') {
        // When abort controller executed
    } else (error.response.status == 401) {
        // When you get http code 401 (Un-authenticated)
        // Eg:
        navigate("/login", { state: { from: location }, replace: true });
    } else {
        // Etc...
    }
}
...
夏末的微笑 2025-02-11 07:05:54

在搜索此问题时,我发现要克服此问题的最佳选择是:

  1. 从应用程序中删除严格模式(您可以通过从应用程序组件中删除stricmode标签来执行此操作)
  2. 使用React Query(您应该在现代React中使用该Quey Query无论如何)

参考:

https://blog.bitsrc.io/react-v18-0-useeffect-bug-why-do-effects-跑步twice-39babecede93

Searching about this issue, I found that the best options to overcome this are:

  1. Remove the StrictMode from your app (you can do this simply by removind the StricMode tag from the App component)
  2. Use React Query (which you should be using in modern React applications anyway)

References:

https://javascript.plainenglish.io/react-18-useeffect-double-call-for-apis-emergency-fix-724b7ee6a646

https://blog.bitsrc.io/react-v18-0-useeffect-bug-why-do-effects-run-twice-39babecede93

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文