react - react router v6- privateRoute - infinite loop or not rendering

Viewed 597

Apologies for this seemingly repated question but it is really biting me. I am trying to use the new ReactRouter v6 private routes and I think the best practice for me would be to make a call to the server to make sure the token is valid and has not been revoked. I am being badly beatean by an infinite loop entering the private route with the typical error

Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

my private route looks like this:


import React, {useCallback, useEffect, useState} from "react"
import {Outlet, Navigate} from "react-router-dom"
import {Auth} from "../../api/authApi"


const  PrivateRoute = () => {
  const [auth, setAuth] = useState(false)

  const checkAuth = useCallback(() => {
    let authApi = new Auth()
    authApi.isAuth().then(isAuthorized => (
      setAuth(isAuthorized)
    ))
  }, [])

  useEffect(() => {
    checkAuth()
  }, [checkAuth])

  return auth ? <Outlet /> : <Navigate to="/login" />;
}

export default PrivateRoute

and my routes are:

function App() {

  return (
     <HashRouter>
       <Routes>
         <Route exact path="/login" element={<LoginPage />} />
         <Route exact path="/register" element={<RegisterPage />} />
         <Route path="/" element={
           <PrivateRoute><HomePage /></PrivateRoute>
         } />
       </Routes>
     </HashRouter>
  )
}

export default App

I changed the PrivateRoute component to this:

import React, {useEffect, useRef} from "react"
import {Outlet, Navigate} from "react-router-dom"
import {Auth} from "../../api/authApi"


const  PrivateRoute = () => {
  let auth = useRef(false)

  useEffect(() => {
    const checkAuth = () => {
      let authApi = new Auth()
      authApi.isAuth().then(isAuthorized => (
        auth.current = isAuthorized
      ))
    }
    checkAuth()
  }, [])

  return (auth.current ? <Outlet /> : <Navigate to="/login" />)
}

export default PrivateRoute

but still have the same issue. Is it something I am missing?

1 Answers

I tried it and found two issues:

  1. The initial state auth is false so it will navigate to /login and unmount PrivateRoute at the first time, and then the component PrivateRoute(unmounted) got api response, I think maybe that's why you got warning. (I made an solution at the bottom)
  2. The Route and Outlet components are used in the wrong way.
         <Route path="/" element={
           <PrivateRoute><HomePage /></PrivateRoute>
         } />

should be modified to

        <Route element={<PrivateRoute />}>
          <Route path="/" element={<Home />} />
        </Route>

The Code Sample :

Edit TextField selectionStart

Related