15

I have a custom hook that will check whether you are logged in, and redirect you to the login page if you are not. Here is a pseudo implementation of my hook that assumes that you are not logged in:

import { useRouter } from 'next/router';

export default function useAuthentication() {

  if (!AuthenticationStore.isLoggedIn()) {
    const router = useRouter();
    router.push('/login'); 
  }
}

But when I use this hook, I get the following error:

Error: No router instance found. you should only use "next/router" inside the client side of your app. https://err.sh/vercel/next.js/no-router-instance

I checked the link in the error, but this is not really helpful because it just tells me to move the push statement to my render function.

I also tried this:

// My functional component
export default function SomeComponent() {

  const router = useRouter();
  useAuthentication(router);

  return <>...</>
}

// My custom hook
export default function useAuthentication(router) {

  if (!AuthenticationStore.isLoggedIn()) {
    router.push('/login');
  }
}

But this just results in the same error.

Is there any way to allow routing outside of React components in Next.js?

juliomalves
  • 42,130
  • 20
  • 150
  • 146
Titulum
  • 9,928
  • 11
  • 41
  • 79

4 Answers4

12

The error happens because router.push is getting called on the server during SSR on the page's first load. A possible workaround would be to extend your custom hook to call router.push inside a useEffect's callback, ensuring the action only happens on the client.

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

export default function useAuthentication() {
    const router = useRouter();

    useEffect(() => {
        if (!AuthenticationStore.isLoggedIn()) {
            router.push('/login'); 
        }
    }, [router]);
}

Then use it in your component:

import useAuthentication from '../hooks/use-authentication' // Replace with your path to the hook

export default function SomeComponent() {
    useAuthentication();

    return <>...</>;
}
Dorklord
  • 416
  • 2
  • 6
  • 17
juliomalves
  • 42,130
  • 20
  • 150
  • 146
7

import Router from 'next/router'

HalfWebDev
  • 7,022
  • 12
  • 65
  • 103
4

If you stumbled upon this while searching on accessing nextjs router outside of react components without using any hooks, you can refer to this answer on a GitHub issue https://github.com/vercel/next.js/discussions/17046

extract from the above reference

import Router from 'next/router'

//Add following line within the required code block
Router.push("/")

2

create a HOC which will wrap your page component

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

export default function UseAuthentication() {
 return () => {
    const router = useRouter();

    useEffect(() => {
      if (!AuthenticationStore.isLoggedIn()) router.push("/login");
    }, []); 
// yous should also add isLoggedIn in array of dependancy if the value is not a function

    return <Component {...arguments} />;
  };
}

main component

function SomeComponent() {


  return <>...</>
}
export default UseAuthentication(SomeComponent)
enoch
  • 2,587
  • 2
  • 15
  • 22
  • 1
    This results in the same error: `Error: No router instance found. You should only use "next/router" inside the client side of your app.` – Titulum Sep 09 '20 at 15:42