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

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


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    };  }


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].jsindex 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-startercd next-learn-startergit checkout 5c2f8513a3dac5ba5b6c7621d8ea0dda881235eacd next-learn-starternpm installnpm 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.