2

So this is more of a javascript question than a reactjs question. I am creating a protected route in reactjs. In this, I am fetching the '/checkauth' get request to check the authentication and it correctly returns the response to me. However the problem is that since it is an async function, it takes time to return that value and thus my return statement is executed earlier. This is the code I am having problem with.

const [auth, setAuth] = useState();

const checkAuthentication = async ()=>{
    const res = await fetch('/checkauth', {
        method : "GET",
        credentials: "include", 
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        }
    });
    const data = await res.json();
    return res.status===200 ? (data.isAuthenticated) : (false) ;
}

useEffect(async ()=>{
    const data = await checkAuthentication();
    setAuth(data)
}, []);

return auth ? <Outlet /> : <Navigate to='/signin' />;

Here the auth is always undefined and thus it always navigates to signing.

  • 1
    You will need to render something else while it's still fetching the value. No way around that. – Bergi May 22 '22 at 20:52

2 Answers2

1

Use three states.

const [auth, setAuth] = useState("loading");

...

setAuth(data ? "auth" : "not-auth");

...

if (auth === "loading")
    return <Loading />
else if (auth === "not-auth")
    return <Navigate to='/signin' />
else 
    return <Outlet />
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Okay, so meant to say that I should create a Loading component and render that if it is in loading state. However, if the `return ` is executed, then the other two statement won't get execute and then the webpage will only be have Loading component. Please help me. – Deepak Sangle May 22 '22 at 20:54
  • @DeepakSangle — Well yes, but when the Ajax request completes the state will change so it won't return the loading component any more. – Quentin May 22 '22 at 20:57
0

You can return a loading spinner while fetching the data, and when the request completes the state will be updated and the <Outlet /> component will be rendered.

By the way: When you are passing an async function to the useEffect hook, it returns a promise and useEffect doesn't expect the callback function to return Promise, rather it expects that the callback returns nothing (undefined) or a function (typically a cleanup function).

Try this:

useEffect(() => {
  // declare the async data fetching function
  const fetchData = async () => {
    // get the data from the api
    const data = await fetch('https://yourapi.com');
    // convert the data to json
    const json = await response.json();

    // set state with the result
    setData(json);
  }

  // call the function
  fetchData()
    // make sure to catch any error
    .catch(console.error);;
}, [])

  • More info:

React Hook Warnings for async function in useEffect: useEffect function must return a cleanup function or nothing

tateccf
  • 115
  • 1
  • 9
  • I think even if i do this, the return statement will be executed earlier and the `auth` set will still be undefined – Deepak Sangle May 22 '22 at 20:58
  • Yes, that's right. You can return a loading spinner while fetching the data, and when the request completes the state will be updated and the will be rendered – tateccf May 22 '22 at 21:06