Q:

React Router: Check that JWT is valid before rendering a Private Route

I'm looking to implement a real world authentication for a React Router app.  Every tutorial I've seen uses fakeAuth to simulate authentication, but doesn't actually implement real world authentication.  I'm trying to actually implement authentication.  Is this possible? 
Right now I'm sending a jwt to the back end to check whether it is valid before returning the Component I want to render -- Redirect to Login if jwt authentication fails, or render Dashboard if it's a valid jwt.  The problem is the ProtectedRoute is returning the redirect to /login before the back end is returning whether the jwt is valid or not. 
How can I get real world authentication in my React-Router app?  Is this even possible? 
const PrivateRoute = ({ component: Component, ...rest }) => {

  const [auth, setAuth] = useState(false);

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

  useEffect(() => {
    // send jwt to API to see if it's valid
    let token = localStorage.getItem("token");
    if (token) {
      fetch("/protected", {
        method: "POST",
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ token })
      })
      .then((res) => {
        return res.json()
      })
      .then((json) => {
        if (json.success) {
          setAuth(true);
        }
      })
      .catch((err) => {
        setAuth(false);
        localStorage.removeItem("token");
      });
    }

  }, [])

  return (<Route {...rest}
    render={(props) => {
      return auth ?  <Component {...props} /> : <Redirect to="/login" />
    }} />)
  }
}

A:

I would say you need a state between authenticated/not valid jwt.  I would use another state field, isTokenValidated (or isLoading):
const PrivateRoute = ({ component: Component, ...rest }) => {

  const [auth, setAuth] = useState(false);
  const [isTokenValidated, setIsTokenValidated] = useState(false);

  useEffect(() => {
    // send jwt to API to see if it's valid
    let token = localStorage.getItem("token");
    if (token) {
      fetch("/protected", {
        method: "POST",
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ token })
      })
      .then((res) => {
        return res.json()
      })
      .then((json) => {
        if (json.success) {
          setAuth(true);
        }
      })
      .catch((err) => {
        setAuth(false);
        localStorage.removeItem("token");
      })
      .then(() => setIsTokenValidated(true));
    } else {
       setIsTokenValidated(true); // in case there is no token
    }

  }, [])

 if (! isTokenValidated) return <div />; // or some kind of loading animation

  return (<Route {...rest}
    render={(props) => {
      return auth ?  <Component {...props} /> : <Redirect to="/login" />
    }} />)
  }
}

