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 }; }
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.
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 .
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.
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.
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.
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].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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With