简体   繁体   中英

useEffect infinite loop with useState

I'm trying to check if authState is true to show my side sidebar to the user. It works but I get an infinite loop.

here is the useEffect and 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]);

Edit: I am actually using a 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>
    </>
  );
}

Update

Using this code now but when I go into, like, lets says /users I need to refresh the page to let authState 's status be recognized as true by the sidebar then the sidebar shows up

  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
        });
      }
    });
  },[]);

here is my sidebar

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>
        }
        </>
    )
}

Since at the end of the useEffect you are changing the authState its calling the useEffect again. I would suggest having a flag to trigger check if the authState is updated and stop the loop, the code might be kinda wrong as i just wrote it here:P, you would have to set the updateAuth to true as well before calling the setAuthState. If you want it to run only at the start as Hamza Khursheed said, just remove the authState from the dependency array (the second argument of the use effect)

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]);

You should adjust your dependency array to reflect on what change you want your useEffect to fire. If you want to get authorization state on route change this should work:

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]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM