javascriptreactjsnext.js

react-router Navigate component in Nextjs


How can i achieve a similar result just like Navigate component of react-router has, in Nextjs? There is a next/Router option but i want to return something to navigate.

i want to redirect the page, but not with router.push because i have to use a useEffect but i only want to know if there is a way to do the exact same thing using returning a component

Basically what is the equivalent of this in Nextjs without react-router

import { Navigate } from "react-router";

const Page = () => {
  const { user } = useAuth();

  if (user?.role.name === "user") {
    return <Navigate to={"/app"} />;
  } else {
    return <Navigate to={"/app/workspaces"} />;
  }
}

export default Page

Solution

  • (New Next.js 13.4 App Router approach)

    My implementation is just a simplified version of the React Router's <Navigate/> component. As noted in the React Router doc, "the v6 <Navigate /> uses push logic by default and you may change it via replace prop". So the default value for replace in my implementation will be false just for API consistency.

    import {useRouter} from 'next/navigation'
    import {useEffect} from 'react'
    
    type NavigateProps = {to: string; replace?: boolean}
    
    export default function Navigate({to, replace = false}: NavigateProps): null {
      const router = useRouter()
    
      useEffect(() => {
        if (replace) {
          router.replace(to)
        } else {
          router.push(to)
        }
      }, [replace, router, to])
    
      return null
    }
    

    And you might consume it at the root layout that wraps all the routes and pages you want to protect (e.g. /protected/* routes):

    // /app/protected/layout.tsx
    'use client'
    
    import {useAuth} from '@scope/react-auth'
    import {Fragment, ReactNode} from 'react'
    import Navigate from '~/components/Navigate'
    
    export default function Layout({children}: {children: ReactNode}) {
      return <RequireLogin>{children}</RequireLogin>
    }
    
    function RequireLogin({children}: {children: ReactNode}) {
      const {currentUser} = useAuth()
    
      return <Fragment>{currentUser ? children : <Navigate to="/ap/login" replace />}</Fragment>
    }
    
    

    ⚠️ According to one of the authors of react-router, using render prop for private routes should be avoided in React Router v6.

    ⚠️ According to the new useRouter() API, the new useRouter hook should be imported from next/navigation and not next/router.