Replace setTimeout in useEffect when waiting for props

Tags: ,



I am looking for a better solution to using setTimeout to wait for props using the useEffect() hook. Currently I have working as intended

const sessionCookie = getCookie('_session');
const { verifiedEmail } = props.credentials;
const [loading, setLoading] = useState(true);
useEffect(() => {
  const timeoutLoading = setTimeout(() => setLoading(false), 2000);
  if (!loading) {
    if (sessionCookie) {
      if (verifiedEmail) {
        window.location.href = 'https://1.example.com';
      }
    } else {
      window.location.href = 'https://2.example.com';
    }
  }
  return () => {
    clearTimeout(timeoutLoading);
  };
}, [loading]);

whereas props.credentials in it’s initial state is {}, awaiting a response from the server to give the value for verifiedEmail and sessionCookie relies on a function getCookie to return whether the cookie exists and the value.

Whilst this works, it’s not ideal. One example would be in some user cases, 2s isn’t enough time, in others it makes the user wait, when the props are already available.

My question is, how can I create a promise or use async/await to achieve the same affect without the risk of using setTimeout.

NOTE: props.credentials are not available on render and will always return an empty object before containing verifiedEmail. In some cases, the sessionCookie may not be available on render too but will also be available before props.credentials has verifiedEmail. If sessionCookie exists, verifiedEmail will too shortly after.

Ideally I would it best to create a promise around getCookie, then ensure the _session is available before identifying verifiedEmail exists. Any thoughts?

getCookie() is as below

const getCookie = (name: string) => {
  const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
  return v ? v[2] : null;
};

Answer

Update

Can you add a new prop called hasAuthenticated or something like that. While your request is pending, this can be false. Once the request is complete, set it to true and apply your logic at that time, just like isLoading.

That should remove the need for timers.

Previous

You could try something like this using two useEffects. First one will handle setting your session cookie and the second one will trigger the window change.

I’m not sure how your getCookie function works though.

const [sessionCookie, setSessionCookie] = useState(null);
const [loading, setLoading] = useState(true);
const { verifiedEmail } = props.credentials;

useEffect(() => {
    const getSession = async () => {
        setSessionCookie(await getCookie('_session'));
        setLoading(false);
    }
    getSession();
}, [setSessionCookie, getCookie, setLoading]);

useEffect(() => {
    if (!loading) {
        if (sessionCookie) {
            if (verifiedEmail) {
                window.location.href = 'https://1.example.com';
            }
        } else {
            window.location.href = 'https://2.example.com';
        }
    }
}, [sessionCookie, verifiedEmail, loading]);


Source: stackoverflow