skip to Main Content

I am using NextJS 14 to setup routing. I am using root layout in app/layout.js to check for jwt tokens and conditionally allow page rendering or redirect to /auth/login.
However in doing so, I am getting 2 back-to-back errors.

  1. First the app is redirected to /auth/login as expected.
  2. Then due to some reason, the /auth/login keeps re-rendering multiple times but with the UI of AppLayout.js (tried putting dummy text in AppLayout and figured it out).
  3. After a few re-renders, the app crashes, nothing is shown on browser and console gives this error:
 ⨯ app/(dashboard)/AppLayout.jsx (10:2) @ Layout
 ⨯ ReferenceError: localStorage is not defined
    at Layout (/home/krush/agro/aggro/.next/server/chunks/_f13a71._.js:137:19)
   8 | export default function Layout({ children }) {
   9 |   const token = localStorage.getItem('token');
> 10 |
     | ^
  11 |   useEffect(() => {
  12 |     if (!token) redirect('/auth/login');
  13 |   }, [token]
// app/layout.js

import AppLayout from './(dashboard)/AppLayout'
import './globals.css'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className + 'w-full'}>
        <AppLayout>
          {children}
        </AppLayout>
      </body>
    </html>
  )
}

This is the AppLayout where I am trying to conditionally authenticate using jwt tokens. The AppLayout is in a (dashboard) group inside NextJS as I only want the layout for the dashboard and not for the auth pages

// app/(dashboard)/AppLayout.js

'use client';

import { redirect } from 'next/navigation';
import { useEffect } from 'react';

export default function Layout({ children }) {
  const token = localStorage.getItem('token');

  useEffect(() => {
    if (!token) redirect('/auth/login');
  }, [token])

  return (
    <div className='flex-1'>
      {children}
    </div>
  )
}

I have no code written yet for auth pages.

// app/auth/login/page.js

export default function Page() {
  return (
    <>
    </>
  )
}

As mentioned above, I simply want to use a layout for the whole dashboard(AppLayout) and that layout should not be displayed in /auth/* so have added a group (dashboard). And AppLayout will be using many Client side React functions so I am taking it out of /app/layout.js

The error is definitely exists in the way I have written the token fetching and useeffect code, but I dont know what exactly the error is and how to resolve it.

2

Answers


  1. the redirection shouldn’t be happening with given route, so that users can access /auth/login.
    also, don’t forget to add route guard for already logged-in users.

    the app crashes because memory has just run out; I’d suggest checking redirection often if possible.

    // ...
      // https://nextjs.org/docs/app/api-reference/functions/use-pathname
      const pathname = usePathname();
      // check redirection in dev environment, to prevent infinite route loop
      useEffect(() => {
        if (process.env.NODE_ENV === 'development') {
          console.log('current path:', pathname);
        }
      }, [pathname]);
    
      // previous code modified
      useEffect(() => {
        // route guard is ignored for '/auth/login'
        if (!token && pathname !== '/auth/login') redirect('/auth/login');
        // and then the same route should be guarded after login
        if (token && pathname === '/auth/login') redirect('/');
      }, [token, pathname])
    
    Login or Signup to reply.
  2. Although you use use client, your client component is first rendered on the server. you can test this by adding this console.log("where am I "); to your layout file. you will see "where am I " is logged both on the terminal and browser console.. that is why, if you are using window.localStorage, you need to make sure you are on the browser environment:

    if (typeof window !== 'undefined') {
      // you should not store token in here.
      const token = localStorage.getItem('token');
      // handle redirect logic here
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search