Reputation: 33
I am currently trying to make a protected route function in react. I wish that result
will return a boolean value rather than a promise without changing ProtectedRoute
to async
:
import React from "react";
import { Redirect, Route } from "react-router-dom";
import { CheckToken } from "./RequestAction"
function ProtectedRoute({ component: Component, ...restOfProps }) {
const result = (async () => {
const res = await CheckToken()
return res;
})()
console.log(result); //log-> Promise {<pending>}[[Prototype]]: Promise[[PromiseState]]: "fulfilled"[[PromiseResult]]: false
return (
<Route
{...restOfProps}
render={(props) =>
result ? <Component {...props} /> : <Redirect to="/login/" />
}
/>
);
}
export default ProtectedRoute;
This is the CheckToken
function:
import axios from "axios";
async function CheckToken() {
let result = null;
await axios
.get(`http://localhost:5000/protected`,
{"withCredentials": true}
)
.then((res) => {
console.log("res.data.status:",res.data)
if (res.data.status === "success") {
result = true
}
})
.catch((err) => {
result = false
});
console.log("result:",result);
return result
}
Upvotes: 3
Views: 1971
Reputation: 349
OK, so in your FunctionComponent you are trying to contact a server on a per render basis, and you are saying you want to capture the result in a boolean, that is then passed onto your child Route component
Firstly, network requests are considered effects, usually triggered by a change in your component props. you would want to handle the network behavior asynchronously as it would block the rendering of the component otherwise, which is something React doesn't allow. Also, you probably only want to check the token in specific circumstances, depending on your props.
You can still render your Route child component once your network request has resolved, but until then, there will be an intermediary state that your component will need to handle. How it does that is up to you, but you should probably not render a link until you have that result information.
I'd introduce a bit of state in a custom hook, and just have your component return out some intermediary state until you get a result / error.
I would also just return a token, you can use null to indicate the network request has not completed, and empty string if one hasn't been retrieved.
const useToken = () => {
const [state, setState] = useState(null)
useEffect(() => {
//TODO: you would also want to catch errors
CheckToken().then(setState)
})
return state
}
function ProtectedRoute({ component: Component, ...restOfProps }) {
const token = useToken()
if (token === null) {
return <Spinner/> // something that indicates you are waiting
}
return (
<Route
{...restOfProps}
render={(props) =>
token ? <Component {...props} /> : <Redirect to="/login/" />
}
/>)
}
}
Upvotes: 1
Reputation: 1050
const useToken = () => {
const [token, setToken] = useState(null);
useEffect(() => {
const f = async () => {
const res = await CheckToken();
//TODO: add check login;
setToken(res);
};
f();
})
return token;
}
function ProtectedRoute({ component: Component, ...restOfProps }) {
const token = useToken();
return (
<Route
{...restOfProps}
render={(props) =>
token ? <Component {...props} /> : <Redirect to="/login/" />
}
/>
);
}
Function component body cannot be async.
Upvotes: 6