im creating a wrapper to check authentication the server response is as expected but somehow the isAuthenticated state does not change to true.
import React, { useState, useEffect } from "react";
import { Navigate } from "react-router-dom";
import Cookies from "js-cookie";
import axios from "axios";
function PrivateRoute({ children }) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
async function checkAuth() {
try {
axios.defaults.withCredentials = true;
const sessionId = Cookies.get("sessionId");
const data = {
sessionId: sessionId,
};
if (sessionId) {
const response = await axios.get("http://127.0.0.1:5000/session", {
params: data,
});
console.log(response.status);
if (response.status === 200) {
console.log("authenticated");
setIsAuthenticated(true);
} else {
console.log("unauthenticated");
setIsAuthenticated(false);
}
}
} catch (err) {
console.error(err);
setIsAuthenticated(false);
}
}
checkAuth();
console.log(isAuthenticated);
return isAuthenticated ? children : <Navigate to="/login" />;
}
export default PrivateRoute;
ive tried to log inside my if statement and it works and when i log isAuthenticated after calling the checkAuth function it remains false.
2
Answers
the checkAuth in your code is an async function so
console.log(isAuthenticated);
is ran beforesetIsAuthenticated(true);
The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the old value that was on the screen before your call. doc
Use useEffect instead of calling the function directly. doc
As others have mentioned, React batches state updates in order to optimize performance, meaning
setState
runs "asynchronously" (though it’s not a Promise-returning function).If you’re not using a client-side caching library like
useSWR
, then per the React documentation, the proper approach is to do data fetching within auseEffect()
. Just make sure to have anignore
flag to avoid potential race conditions, as well as add support for anull
state for when the request is still loading (a.k.a. before you decide to give the user access or navigate them away). In the end, your component should look something like this: