【问题标题】:React Hook SetState Causing Infinite LoopReact Hook SetState 导致无限循环
【发布时间】:2021-02-13 21:58:34
【问题描述】:

以下是我的代码,我试图在我的注销按钮内调用 setState,因为此按钮仅在 Auth0 isLoggedIn 为真时呈现。 这似乎导致了无限循环,我的猜测是因为正在调用 Auth0 API 每次。我正在关注本教程:https://www.youtube.com/watch?v=35lXWvCuM8o 唯一的区别是我试图在没有 onClick 函数的情况下调用 setState, 谁能给我解释一下问题和解决方法,提前谢谢!

我知道我可以使用 localStorage 来维护用户登录会话,但我这样做纯粹是为了学习 React Hooks,

import React, { useState, useContext, useCallback} from 'react';
    import { useAuth0 } from '@auth0/auth0-react';
    import { ValueContext } from './ValueContext'

    const LogoutButton = () => {
 
    const [login, setLogin] = useContext(ValueContext);


  const { logout, isAuthenticated } = useAuth0();
  const updateLogin = () => {
    setLogin({loggedIn:'false'});
  };

  return (
    
    isAuthenticated && (
      <>
      <button onClick={() => logout()}>
        Log Out
      </button>
      
      <h1>{login.loggedIn}</h1>
     {updateLogin()}
   
          
         
       
      
    
      </>
      
    )

【问题讨论】:

    标签: reactjs react-hooks components infinite-loop setstate


    【解决方案1】:

    您在渲染函数内部调用updateLogin(),因此您在每次渲染时都设置了loggedIn: true。不要将函数或控制台日志直接放在返回函数中,如果必须,将它们放在主 LogoutButton 函数体中。但updateLogin() 只能在某些 onPress 内部调用。

    【讨论】:

    • 我把我的按钮改成了这样:
    • 但现在我得到了一个无限循环的重新渲染。
    • 我对你在这里想要完成的事情感到困惑。我不知道 Auth0 是如何工作的,但我假设您不想在同一个按钮中调用 logoutupdateLogin(它只会让您登录)。
    • 我正在尝试调用 auth0 的登录函数,该函数通过 auth0 对用户进行身份验证。在用户进行身份验证的同时,我想通过上下文更新一个全局变量“loggedIn”,这样我就可以为我的其他组件小夜曲,让用户对他们在未登录时无法访问的某些事物具有新的访问权限,即为什么我最初尝试在没有 onClick 的情况下自行调用 updateLogin()
    • 那你为什么要调用 Auth0 的 logout 如果你试图让用户登录到 Auth0?
    【解决方案2】:

    每次渲染组件时,您都会调用 updateLogin()。这将设置状态变量 loggedIn。这将导致组件再次渲染,并且进程不断循环。

    【讨论】:

      【解决方案3】:

      唯一的区别是我尝试在没有 onClick 函数的情况下调用 setState

      这是一个很大的不同! setState 不应在渲染函数的主体中调用,或者至少有条件地调用它。否则你会得到 setState -> render -> setState -> render ->... 没完没了。

      你可以试试这个:

          let alreadySet = false;
      
          const LogoutButton = () => {
          const [login, setLogin] = useContext(ValueContext);
          const { logout, isAuthenticated } = useAuth0();
          const updateLogin = () => {
            setLogin({loggedIn:'false'});
          };
      
          if(!alreadySet){
            alreadySet = true;
            updateLogin()
          }
      
          return ( 
          isAuthenticated && (
            <>
            <button onClick={() => logout()}>
              Log Out
            </button>   
            <h1>{login.loggedIn}</h1>
            </>
          )
      

      注意这一点

          let alreadySet = false;
      ....
      {
          if(!alreadySet){
            alreadySet = true;
            updateLogin()
          }
      }
      

      这意味着loginIn只会更新一次。是你想要的吗?如果不是。您可以使用更多详细信息更新您的问题:)

      【讨论】:

      • 我添加了您所指的 sn-p,现在出现错误:超出最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,可能会发生这种情况。 updateLogin src/components/LogoutButton.js:14 11 | const { 注销,isAuthenticated } = useAuth0(); 12 |常量更新登录 = () => { 13 | /* 登出(); */ > 14 | setLogin({loggedIn:'false'}); | ^ src/components/LogoutButton.js:22 19 |让已经设置=假; 20 |如果(!已经设置){ 21 |已经设置=真; |更新登录() | }
      • 好的,我更改了 sn-p tolet alreadySet = false; if(!alreadySet && isLoggedIn){ alreadySet = true;更新登录()}
      • 现在应用程序可以正常工作并正确显示登录按钮,但是一旦我单击登录,并且呈现注销按钮,我再次获得 setLogin 的无限循环,所以我需要弄清楚如何防止它重新更新已经设置回false,有什么想法吗?
      • 嗨 Josh,抱歉回复晚了,我们应该移动“让 alreadySet = false;”在 LogoutButton 函数之外
      【解决方案4】:

      如果需要在isAuthenticated为真时使用updateLogin,可以添加useEffect hook。

      喜欢这个

      useEffect(()=>{ if (isAuthenticated){
         setLogin({loggedIn:'false'});
      }},[isAuthenticated, setLogin] );

      【讨论】:

        猜你喜欢
        • 2021-02-19
        • 1970-01-01
        • 1970-01-01
        • 2020-06-04
        • 1970-01-01
        • 2020-09-06
        • 2021-11-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多