Denis2310
Denis2310

Reputation: 1208

ReactJs/NextJS - automatic redirect after 5 seconds to another page

Console.log() always returns 5, so basically on frontend I always see this sentence: Welcome, you have successfully logged in, you will be redirected in.. 4

Looks like that because setRedirectSeconds() is asynchronous, it wont update state right at the moment and whenever my setInterval function starts again, redirectSeconds will still be 5 each time.

How to fix that?

Here is my code:

const Welcome: NextPage = (): ReactElement => {
const [redirectSeconds, setRedirectSeconds] = useState<number>(5);
const router = useRouter();
const query = router.query;

useEffect(() => {
    if (query?.redirect) {
        setTimeout(() => {
            const interval = setInterval(() => {
                console.log(redirectSeconds);
                if (redirectSeconds > 0) {
                    setRedirectSeconds(redirectSeconds - 1);
                } else {
                    clearInterval(interval);
                    router.push(query.redirect.toString());
                }
            }, 1000)
        }, 1000);
    }
}, []);

return (
        <div>
            Welcome, you have successfully logged in, you will be redirected in.. {redirectSeconds}
        </div>
);
};

export default Welcome;

Upvotes: 6

Views: 7820

Answers (3)

Yilmaz
Yilmaz

Reputation: 49331

Set a top level state variable. when it hits 0, redirect the user

  import { useNavigate } from "react-router-dom";

  const [count, setCount] = useState(5);

Inside useEffect write a setInterval to decrease count by 1 after 1000ms

const navigate = useNavigate();
useEffect(()=>{
   // each second count=count-1
   const interval=setTimeInterval(()=>{
            setCount((updatedCount)=>updatedCcount-1)
        },1000)
    // if count===0 redirect

    count==0 && navigate(`/${query.redirect.toString()}`)

    // always clear the timeers in return function
    return ()=>{
          clearIntercal(interval)
    }

},[count,navigate])

then write the message.

     p>
      This page cannot be found. Redirecting to homepage in
      {count} {count > 1 ? 'seconds' : 'second'}.
    </p>

Upvotes: 0

user3109582
user3109582

Reputation: 81

You can use the below custom hook to achieve this functionality.

import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';

export default function useRedirectAfterSomeSeconds(redirectTo, seconds = 5) {
  const [secondsRemaining, setSecondsRemaining] = useState(seconds);
  const router = useRouter();

  useEffect(() => {
    if (secondsRemaining === 0) router.push('/');

    const timer = setTimeout(() => {
      setSecondsRemaining((prevSecondsRemaining) => prevSecondsRemaining - 1);
      if (secondsRemaining === 1) router.push(redirectTo);
    }, 1000);

    return () => {
      clearInterval(timer);
    };
  }, [router, secondsRemaining, redirectTo]);

  return { secondsRemaining };
}

Usage example:

import Head from 'next/head';
import useRedirectAfterSomeSeconds from '../hooks/useRedirectAfterSomeSeconds';

export default function ErrorPage() {
  const { secondsRemaining } = useRedirectAfterSomeSeconds('/', 5);

  return (
    <>
      <Head>
        <title>Page not found - redirecting in 5 seconds</title>
      </Head>
      <main>
        <h1>404</h1>
        <p>
          This page cannot be found. Redirecting to homepage in
          {secondsRemaining} {secondsRemaining > 1 ? 'seconds' : 'second'}.
        </p>
      </main>
    </>
  );
}

Upvotes: 1

Denis2310
Denis2310

Reputation: 1208

Here is how I adjusted it and now it works fine:

  • I have removed setInterval and added dependancy to useEffect function. And I have added timeout of 1000ms before decreasing redirectSeconds.

     useEffect(() => {
     if (query?.redirect) {
         if (redirectSeconds == 0) {
             router.push(query.redirect.toString());
             return;
         }
    
         setTimeout(() => {
             console.log(redirectSeconds);
             setRedirectSeconds((redirectSeconds) => redirectSeconds - 1);
         }, 1000)
     }
    }, [redirectSeconds]);
    

Upvotes: 7

Related Questions