Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use "useRouter()" from next.js in a class component?

Tags:

I was trying to get the queries from my url pattern like localhost:3000/post?loc=100 by using useRouter() from "next/router" and fetching some data using that id from my server. It worked when I used it in a Stateless Functional Component.

But the page showing "Invalid hook call" then. I tried calling getInitalProps() of a Stateless Functional Component, but it didn't work there either and showed the same error. Is there any rule to use this method?

I was developing a front-end using React Library and Next.js Framework.

constructor(props) {   this.state = {     loc: useRouter().query.loc,     loaded: false   }; } 
like image 835
Shakirul Hasan Avatar asked Jul 14 '19 12:07

Shakirul Hasan


People also ask

How do I use NextJs useRouter?

Method 1: Using useRouter() Method: In NextJs we can easily get the value of the current route using the useRouter() function. To use this we are going to create a new page inside our pages directory with the name 'get-route. js'. After that, we will add the below code in our get-route.

How do you find the current route in React class component?

Use the useLocation() hook to get the current route with React Router, e.g. const location = useLocation() . The hook returns the current location object. For example, you can access the pathname as location. pathname .

Can we use React router in next JS?

In React JS, we would install a package called react-router-dom to implement routing inside the application. But Next JS has its own inbuilt router from the next/link , with which we can navigate between the pages. Before using the next/link , we need to set up the different pages/routes inside the pages folder.

Does NextJs use client side routing?

The Next. js router allows you to do client-side route transitions between pages, similar to a single-page application. A React component called Link is provided to do this client-side route transition.


2 Answers

Hooks can be used only inside functional components, not inside classes. I would recommend to use withRouter HOC as per next.js documentation:

use the useRouter hook, or withRouter for class components.

Or see From Classes to Hooks if you want to switch to hooks.


In general, it's possible to create a wrapper functional component to pass custom hooks into class components via props (but not useful in this case):
const MyClassWithRouter = (props) => {   const router = useRouter()   return <MyClass {...props} router={router} /> }  class MyClass...   constructor(props) {     this.state = {       loc: props.router.query.loc,       loaded: false     };   } 
like image 149
Aprillion Avatar answered Sep 28 '22 00:09

Aprillion


withRouter example

https://stackoverflow.com/a/57029032/895245 mentioned it, but a newbie like me needed a bit more details. A more detailed/direct description would be:

Function component:

import { useRouter } from "next/router";  export default function Post() {   const router = useRouter();   return (     <div>{ router.query.id }</div>   ) } 

Class component equivalent:

import { withRouter } from 'next/router' import React from "react";  export default withRouter(class extends React.Component {   render() {     return (       <div>{ this.props.router.query.id }</div>     )   } }) 

I tested this out more concretely as follows. First I took vercel/next-learn-starter/basics-final/pages/posts/[id].js and I hacked it to use the router:

diff --git a/basics-final/pages/posts/[id].js b/basics-final/pages/posts/[id].js index 28faaad..52954d3 100644 --- a/basics-final/pages/posts/[id].js +++ b/basics-final/pages/posts/[id].js @@ -4,13 +4,17 @@ import Head from 'next/head'  import Date from '../../components/date'  import utilStyles from '../../styles/utils.module.css'   +import { useRouter } from "next/router" +  export default function Post({ postData }) { +  const router = useRouter();    return (      <Layout>        <Head>          <title>{postData.title}</title>        </Head>        <article> +        <div>router.query.id = {router.query.id}</div>          <h1 className={utilStyles.headingXl}>{postData.title}</h1>          <div className={utilStyles.lightText}>            <Date dateString={postData.date} /> 

Then, I ran it as:

git clone https://github.com/vercel/next-learn-starter cd next-learn-starter git checkout 5c2f8513a3dac5ba5b6c7621d8ea0dda881235ea cd next-learn-starter npm install npm run dev 

Now when I visit: http://localhost:3000/posts/ssg-ssr I see:

router.query.id = ssg-ssr 

Then I converted it to the class equivalent:

import Layout from '../../components/layout' import { getAllPostIds, getPostData } from '../../lib/posts' import Head from 'next/head' import Date from '../../components/date' import utilStyles from '../../styles/utils.module.css'  import { withRouter } from 'next/router' import React from "react"   export default withRouter(class extends React.Component {   render() {     return (       <Layout>         <Head>           <title>{this.props.postData.title}</title>         </Head>         <article>           <div>router.query.id = {this.props.router.query.id}</div>           <h1 className={utilStyles.headingXl}>{this.props.postData.title}</h1>           <div className={utilStyles.lightText}>             <Date dateString={this.props.postData.date} />           </div>           <div dangerouslySetInnerHTML={{ __html: this.props.postData.contentHtml }} />         </article>       </Layout>     )   } })  export async function getStaticPaths() {   const paths = getAllPostIds()   return {     paths,     fallback: false   } }  export async function getStaticProps({ params }) {   const postData = await getPostData(params.id)   return {     props: {       postData     }   } } 

and everything seemed to be unchanged.

Tested on Next.js 10.2.2.