【问题标题】:useEffect infinite loop with useState带有 useState 的 useEffect 无限循环
【发布时间】:2021-08-28 02:42:47
【问题描述】:

我正在尝试检查 authState 是否为真,以便向用户显示我的侧边栏。它有效,但我得到一个无限循环。

这里是useEffect和useState

const [ authState, setAuthState ] = useState({
      username: "", 
      id: 0, 
      status: false
    });

useEffect(() => {
   axios.get('http://localhost:4000/users/auth/v', {withCredentials: true}).then((res) => {
        console.log(res.data);
        if (res.data.error) {
          setAuthState({ ...authState, status: false });
        } else {
          setAuthState({
            username: res.data.username, 
            id: res.data.id, 
            status: true
          });
          console.log(authState);
        }
      });

  },[authState]);

编辑:我实际上是在使用一个useContext

  return (
    <>
      <AuthContext.Provider value={{ authState, setAuthState }}>
        <Router>
        <Sidebar />
          <Switch>
            <Route path='/' exact component={Auth} />
            <Route path='/users/add' exact component={AddUser} />
            <Route path='/users' exact component={UserList} />
            <Route path='/users/:id' exact component={UserEdit} />
            <Route path='/roles/add' exact component={AddRole} />
            <Route path='/roles' exact component={RoleList} />
            <Route path='/roles/:roleId' exact component={EditRole} />
            <Route path='/logout' exact component={Logout} />
          </Switch>
        </Router>
      </AuthContext.Provider>
    </>
  );
}

更新

现在使用此代码,但是当我进入时,比如说/users,我需要刷新页面以让侧边栏将authState 的状态识别为true然后显示侧边栏

  useEffect(() => {
    axios.get('http://localhost:4000/users/auth/v', {withCredentials: true}).then((res) => {
      console.log(res.data);
      if (res.data.error) {
        setAuthState({ ...authState, status: false });
      } else {
        setAuthState({
          username: res.data.username, 
          id: res.data.id, 
          status: true
        });
      }
    });
  },[]);

这是我的侧边栏

function Sidebar() {

    const [ sidebar, setSidebar ] = useState(false);

    let userData = localStorage.getItem('user');
    // console.log(userData);

    const { authState } = useContext(AuthContext);
    

    const showSidebar = () => setSidebar(!sidebar)

    return (
        <>
        {authState.status &&
        <Styles>
            <Navbar bg="light">
            <Navbar.Brand>
                <NavIcon>
                    <MenuIcon onClick={showSidebar} />
                </NavIcon>
            </Navbar.Brand>
            <Navbar.Text className="user-options">
                <span className='user-name'>Hello, {userData}!</span> {/* WIP input user's fname and lname via context */}
                <span className='logout-link'><Link to="/logout">Logout</Link></span>
            </Navbar.Text>
            </Navbar>
            <Sidenav sidebar={sidebar}>
                <SidebarWrap>
                    <NavIcon>
                        <HighlightOffIcon onClick={showSidebar} />
                    </NavIcon>
                    <SidebarList>
                        {SidebarData.map((val, key) => {
                            return (
                                <li 
                                    key={key}
                                    className='row'

                                > 
                                    <Link 
                                    className='link-style' 
                                    to={val.link}
                                    id={window.location.pathname === val.link
                                        ? "active"
                                        : ""}
                                        >
                                        <SideIcon>{val.icon}</SideIcon>
                                        <SideTitle>{val.title}</SideTitle> 
                                    </Link>
                                </li>
                            )
                        })}
                    </SidebarList>
                </SidebarWrap>
            </Sidenav>
        </Styles>
        }
        </>
    )
}

【问题讨论】:

标签: reactjs react-hooks use-effect use-state use-context


【解决方案1】:

由于在 useEffect 结束时您正在更改 authState,因此它再次调用 useEffect。我建议有一个标志来触发检查 authState 是否已更新并停止循环,代码可能有点错误,因为我刚刚在这里写了:P,在调用 setAuthState 之前,您还必须将 updateAuth 设置为 true。如果你希望它只在开始时像 Hamza Khursheed 所说的那样运行,只需从依赖数组中删除 authState(使用效果的第二个参数)

const [ authState, setAuthState ] = useState({
  username: "", 
  id: 0, 
  status: false
});
const [ updateAuth, setUpdateAuthState ] = useState(false)

 useEffect(() => {
  if(updateAuth){
    axios.get('http://localhost:4000/users/auth/v', {withCredentials: 
        true}).then((res) => {
       console.log(res.data);
    if (res.data.error) {
      setAuthState({ ...authState, status: false });
    } else {
      setAuthState({
        username: res.data.username, 
        id: res.data.id, 
        status: true
      });
      setUpdateAuthState(false);
      console.log(authState);
    }
  });
 }
 },[authState]);

【讨论】:

  • 您应该收到类似“updateAuth 不在useEffect 的部门列表中”的警告。然后,当您添加它时,您会返回到初始问题(您设置了一个触发useEffect 的状态,该useEffect 会生成一个无限循环)。仅当您将 updateAuth 定义为 useRef() 时,您的解决方法才有效(但仍然是一种解决方法)。
  • 好点,我认为它可以被忽略,或者只是添加到依赖列表中,它将被第二次调用,但在 updateAuth 标志处停止执行 useEffect,因为 updateAuth 或如果 updateAuth 为 false,则更新 authState,然后循环停止,我们不会收到任何警告。
  • 在您的代码中,axios.get 将永远不会被执行,因为updateAuth 的初始状态设置为false。无论如何,即使使用此解决方法您避免了第二次 axios.get 调用,您也不会避免 useEffect 一次又一次地验证 if 条件......而且,一个建议,永远不要忽略 React 的警告。
【解决方案2】:

您应该调整依赖数组以反映您希望 useEffect 触发的更改。如果您想在路由更改时获得授权状态,这应该可以:

React.useEffect(() => {
    axios
        .get('http://localhost:4000/users/auth/v', { withCredentials: true })
        .then((res) => {
            console.log(res.data);
            if (res.data.error) {
                setAuthState({ ...authState, status: false });
            } else {
                setAuthState({
                    username: res.data.username,
                    id: res.data.id,
                    status: true,
                });
                console.log(authState);
            }
        });
}, [window.location.pathname]);

【讨论】:

    猜你喜欢
    • 2020-02-21
    • 2021-05-17
    • 2021-04-29
    • 2020-10-16
    • 2020-07-24
    • 1970-01-01
    • 2020-12-04
    • 2021-12-09
    • 2020-02-22
    相关资源
    最近更新 更多