NextJS App Router - redirect() in useEffect hook

I'm currently working on a Next.js 13.4.9 project and I'm facing an issue with redirecting logged in users within a client component using the useEffect hook. I have tried a certain method, but it keeps throwing an error in the browser (NEXT_REDIRECT).

import { redirect } from 'next/navigation';

useEffect(() => {
    getRedirectResult(auth).then( async (userCredential) => {
        if (!userCredential) return;

        fetch('/api/auth/login', {
          method: 'POST',
          headers: {
            Authorization: 'Bearer ' + (await userCredential.user.getIdToken()),
          },
        }).then((res) => {
          if (res.ok) {
            try {
              redirect('/user')
            } catch (error) {
              console.log(error)
            }
          }
        })
      })
}, [])

I would really appreciate it if someone could guide me through the correct approach to redirect logged in users in Next.js using the useEffect hook. Is there an alternative method I should consider? I don't really want to use a router. Thank you in advance for your help!

Error:

Error: NEXT_REDIRECT at getRedirectError (webpack-internal:///(app-client)/./node_modules/next/dist/client/components/redirect.js:40:19) at redirect (webpack-internal:///(app-client)/./node_modules/next/dist/client/components/redirect.js:50:11) at eval (webpack-internal:///(app-client)/./src/app/(auth)/signin/page.tsx:34:82)

Upvotes: 4

Views: 6611

Answers (2)

raas
raas

Reputation: 138

if you want use redirect you can't use redirect in try, you must use redirect in catch or after try catch. this is because redirect() work is by throwing an error that Next.js can handle in order to stop execution of the code.

Here is a the link relevant, for this case : https://github.com/vercel/next.js/issues/49298#issuecomment-1542055642

Upvotes: 2

Fabio Nettis
Fabio Nettis

Reputation: 2853

As far as I know, the redirect method is meant to be used on the server only. You should use the useRouter hook when you are running code on the client side. Here is an example:

"use client";

// or `next/router` when using pages directory
import { useRouter } from "next/navigation";
import { useEffect, useCallback } from "react";

export default function ClientComponent(props) {
  const router = useRouter();

  // wrapped in `useCallback` to avoid re-creating the function on each render
  const redirect = useCallback(async () => {
    try {
      const userCredential = await getRedirectResult(auth);
      const token = await userCredential.user.getIdToken();

      const response = await fetch("/api/auth/login", {
        method: "POST",
        headers: { Authorization: `Bearer ${token}` },
      });

      // you could call also call `router.replace`
      if (response.ok) return router.push("/user");
      
      // handle any response errors here
    } catch (error) {
      // handle any network errors here
    }
  }, [router]);

  useEffect(() => {
    // you could also define the function here without `useCallback`,
    // this is only done when the function only needs to be called
    // inside the effect.
    redirect();
  }, []);

  // ...
}

I am calling router.push here. You could also call router.replace, this would replace the current route with your /user page rather than pushing a new entry into the window's history object.

Upvotes: 1

Related Questions