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, orwithRouter
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.