When I click on a link in my /index.js, it brings me to /about.js page.
However, when I'm passing parameter name through URL (like /about?name=leangchhean) from /index.js to /about.js, I don't know how to get it in the /about.js page.
index.js
import Link from 'next/link';
export default () => (
<div>
Click{' '}
<Link href={{ pathname: 'about', query: { name: 'leangchhean' } }}>
<a>here</a>
</Link>{' '}
to read more
</div>
);
Use router-hook.
You can use the useRouter hook in any component in your application.
https://nextjs.org/docs/api-reference/next/router#userouter
pass Param
import Link from "next/link";
<Link href={{ pathname: '/search', query: { keyword: 'this way' } }}><a>path</a></Link>
Or
import Router from 'next/router'
Router.push({
pathname: '/search',
query: { keyword: 'this way' },
})
In Component
import { useRouter } from 'next/router'
export default () => {
const router = useRouter()
console.log(router.query);
...
}
Using Next.js 9 or above you can get query parameters:
With router:
import { useRouter } from 'next/router'
const Index = () => {
const router = useRouter()
const {id} = router.query
return(<div>{id}</div>)
}
With getInitialProps:
const Index = ({id}) => {
return(<div>{id}</div>)
}
Index.getInitialProps = async ({ query }) => {
const {id} = query
return {id}
}
url prop is deprecated as of Next.js version 6:
https://github.com/zeit/next.js/blob/master/errors/url-deprecated.md
To get the query parameters, use getInitialProps:
For stateless components
import Link from 'next/link'
const About = ({query}) => (
<div>Click <Link href={{ pathname: 'about', query: { name: 'leangchhean' }}}><a>here</a></Link> to read more</div>
)
About.getInitialProps = ({query}) => {
return {query}
}
export default About;
For regular components
class About extends React.Component {
static getInitialProps({query}) {
return {query}
}
render() {
console.log(this.props.query) // The query is available in the props object
return <div>Click <Link href={{ pathname: 'about', query: { name: 'leangchhean' }}}><a>here</a></Link> to read more</div>
}
}
The query object will be like: url.com?a=1&b=2&c=3 becomes: {a:1, b:2, c:3}
For those looking for a solution that works with static exports, try the solution listed here: https://github.com/zeit/next.js/issues/4804#issuecomment-460754433
In a nutshell, router.query works only with SSR applications, but router.asPath still works.
So can either configure the query pre-export in next.config.js with exportPathMap (not dynamic):
return {
'/': { page: '/' },
'/about': { page: '/about', query: { title: 'about-us' } }
}
}
Or use router.asPath and parse the query yourself with a library like query-string:
import { withRouter } from "next/router";
import queryString from "query-string";
export const withPageRouter = Component => {
return withRouter(({ router, ...props }) => {
router.query = queryString.parse(router.asPath.split(/\?/)[1]);
return <Component {...props} router={router} />;
});
};
Get it by using the below code in the about.js page:
// pages/about.js
import Link from 'next/link'
export default ({ url: { query: { name } } }) => (
<p>Welcome to About! { name }</p>
)
I know 2 ways to do this:
A Server-Side way, and a Client-Side way.
Method #1: SSR (Server-Side Rendering):
You should use Query Context for that page.
So use getServerSideProps instead of getStaticProps
import React from "react";
export async function getServerSideProps(context) {
const page = (parseInt(context.query.page) || 1).toString();
// Here we got the "page" query parameter from Context
// Default value is "1"
const res = await fetch(`https://....com/api/products/?page=${page}`);
const products = await res.json();
return {props: {products: products.results}}
// will be passed to the page component as props
}
const Page = (props) =>{
const products = props.products;
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>);
}
export default Page
The reason is that: this data cannot be pre-rendered ahead of user's request, so it must be Server-Side Rendered (SSR) on every request.
Static Pages: Use getStaticProps
Changing Content: use getServerSideProps
And here the content is changing based on query Parameters
Reference: https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props
Method #2: Next Router (Client Side):
import {useState, useEffect} from "react";
import { useRouter } from 'next/router'
const Page = () =>{
const [products, setProducts] = useState([]);
const [page, setPage] =useState((useRouter().query.page || 1).toString());
// getting the page query parameter
// Default value is equal to "1"
useEffect(()=>{
(async()=>{
const res = await fetch(`https://....com/api/products/?page=${page}`);
const products = await res.json();
setProducts(products.results);
// This code will be executed only once at begining of the loading of the page
// It will not be executed again unless you cahnge the page
})()
},[page]);
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
}
export default Page
Reference: https://nextjs.org/docs/api-reference/next/router
If you need to retrieve a URL query from outside a component:
import router from 'next/router'
console.log(router.query)
import { useRouter } from 'next/router';
function componentName() {
const router = useRouter();
console.log('router obj', router);
}
We can find the query object inside a router using which we can get all query string parameters.
Using {useRouter} from "next/router"; helps but sometimes you won't get the values instead u get the param name itself as value.
This issue happens when u are trying to access query params via de-structuring like:
let { categoryId = "", sellerId = "" } = router.query;
and the solution that worked for me is try to access the value directly from query object:
let categoryId = router.query['categoryId'] || '';
let sellerId = router.query['sellerId'] || '';
Post.getInitialProps = async function(context) {
const data = {}
try{
data.queryParam = queryString.parse(context.req.url.split('?')[1]);
}catch(err){
data.queryParam = queryString.parse(window.location.search);
}
return { data };
};
import { useRouter } from 'next/router'
const Home = () => {
const router = useRouter();
const {param} = router.query
return(<div>{param}</div>)
}
Also you can use getInitialProps, more details refer the below tutorial.
get params from url in nextjs
What worked for me in Nextjs 13 pages in the app directory (SSR)
Pass params and searchParams to the page:
export default function SomePage(params, searchParams) {
console.log(params);
console.log(searchParams);
return <div>Hello, Next.js!</div>;
With some builds there may be a bug that can be solved by adding:
export const dynamic='force-dynamic';
especially when deploying on Vercel.
ref: https://beta.nextjs.org/docs/api-reference/file-conventions/page#searchparams-optional
https://github.com/vercel/next.js/issues/43077
Related
I'm facing the following error when using useRouter hook by nextjs.
TypeError: url.startsWith is not a function
import { useRouter } from 'next/router'
const router = useRouter()
function onAppointmentConfirmed() {
const fakeData = '12321'
router.push({
pathname: '/appointment/success',
query: {
data: fakeData,
},
})
}
I have a button that triggers this function in order to redirect but I need to pass some data to the next screen (eg fakeData). This -> router.push('/appointment/success') works but I cannot carry any data onto the next screen.
edit :
import { useRouter } from 'next/router'
export default function index() {
const router = useRouter()
const handleClick = () => {
router.push({
pathname: '/',
query: {
data: 'data',
},
})
}
return <button onClick={() => handleClick()}>Click me to redirect</button>
}
This question already has an answer here:
How to access route parameter inside getServerSideProps in Next.js?
(1 answer)
Closed 1 year ago.
I have created simple application, I passed number value menuApi.js to [catId].js, after can't pass catId value is 26(i.e)http://localhost:3000/category/26, Now I pass catId inside of getServersideProps method but not working. What I am missing.
menuApi.js
import React, { Component } from 'react';
import { Grid, Image } from "semantic-ui-react";
import Link from 'next/link';
function MenuApi(props) {
return (
<Grid className="home-icon">
<Grid.Row centered doubling columns={8} mobile>
{props.menu.map((x, i) => (
<Grid.Column centered key={i} Style="width: 9%!important;">
<Link
href={'/category/'+x.id}
>
<Image src={x.image} alt=""/>
</Link>
<Link href={x.category_url}>
<p >{x.store_name}</p>
</Link>
</Grid.Column>
))}
</Grid.Row>
</Grid>
)
}
export default MenuApi;
[catId].js
import { useRouter } from 'next/router'
const Post = (props) => {
console.log(props.ruslt)
return <p>Post: {storeId}</p>
}
const router = useRouter()
const { storeId } = router.query
export async function getServerSideProps(context) {
const offerList = await fetch('http://localhost:3000/api/v4/web/list',{
method:'POST',
body: JSON.stringify(storeId),
headers: { "Content-Type": "application/json" },
})
const offerData = await offerList.json();
const result=offerData.stores;
return {
props: {
result,
},
};
}
export default Post
You are using useRouter hook outside of a functional component. Hooks can only be used inside of a functional component instead of getServerSideProps .
It should be like this:
const Post = (props) => {
const router = useRouter()
const { storeId } = router.query
console.log(props.result)
return <p>Post: {storeId}</p>
}
Also, you should use getStaticProps instead of getServerSideProps. getServerSideProps will render the page on each request, so your response time will increase.
Instead use getStaticProps which will pre-render your page so response time will reduce.
Data Fetching in Next
The following code should fix it. You seem to be passing the props wrong from the getServerSideProps function
import { useRouter } from 'next/router'
const Post = (props) => {
console.log(props.result)
return <p>Post: {props.storeId}</p>
}
const router = useRouter()
const { storeId } = router.query
export async function getServerSideProps(context) {
const offerList = await fetch('http://localhost:3000/api/v4/web/list',{
method:'POST',
body: storeId,
headers: { "Content-Type": "application/json" },
})
const offerData = offerList;
const result=offerData.stores;
return {
props: {
result,
storeId
},
};
}
export default Post
I would like to use the film title in my route URL (eg films/fletch), but the subsequent getServerSideProps request requires the episode_id.
How do I pass both film.episode_id and film.title to films/[id]/index.js?
Movies.js
<Link
href={{
pathname: `/films/[id]`,
query: {
id: film.episode_id
},
}}
as={`/films/${encodeURIComponent(film.title)}`} >
<a>{film.title}</a>
</Link>
films/[id]/index.js
import {useRouter} from 'next/router'
const movie = () => {
const router = useRouter();
console.log(router);
const { id } = router.query
return (
<div>Movie page for <strong>{id}</strong></div>
)
}
You can use context.query to get the query params of the link.
// films/[id]/index.js
import PropTypes from 'prop-types'
const Movie = ({ query }) => {
return (
<div>Movie page for <strong>{query.id}</strong></div>
)
}
Movie.propTypes = {
query: PropTypes.shape({
id: PropTypes.string,
})
}
export async function getServerSideProps(context) {
return {
props: { query: context.query }
}
}
export default Movie
I am trying to pass one data object to another page, but I can't fetch the data on the second page. below code is I am using
The first page pass the data in LINK
<Link to={{ pathname: `${path}/users/${organization.id}`,
data: organization
}}> <img src={config.s3Bucket + "/" + organization.logo} />
</Link >
Here I am passing the object in the 'data' parameter
Second page
import React, { useState, useEffect } from 'react';
function UserList({ history, match }) {
const { path } = match;
const { id } = match.params;
const [organization, setOrganization] = useState(null);
// const { data } = this.props.location
useEffect(() => {
// console.log(location.data);
}, []); } export { UserList };
I have tried the 'location.data' and 'this.props.location' but I can't fetch the data, please help me to solve this issue.
You can do it like this
<Link to={{ pathname: `${path}/users/${organization.id}`, state: organization}}>
<img src={config.s3Bucket + "/" + organization.logo} />
</Link >
and in the Second Page
import React, { useState, useEffect } from 'react';
import {useLocation} from 'react-router-dom';
function UserList({ history, match }) {
const { path } = match;
const { id } = match.params;
const [organization, setOrganization] = useState(null);
const { state } = useLocation();
useEffect(() => {
console.log(state);
}, []);
}
export { UserList };
use withRouter
import { withRouter } from "react-router-dom"
export default withRouter(ComponentName)
GraphQL queries in my components are not running on dynamic routes when I try to access the query string with router.query.xxx.
I have the following file
// ./pages/section/[slug].js
import { useRouter } from 'next/router';
import AppLayout from '../../components/styles/_AppLayout';
const Section = () => {
const router = useRouter();
return <AppLayout>Hi</AppLayout>;
};
export default Section;
The page displays fine, but as soon as I add {router.query.slug} and refresh the page, it gives me a TypeError because the GraphQL queries do not run. As you can see in the image below, me.firstName is undefined because the GraphQL query did not run
This is the code in _AppLayout.js
import styled from 'styled-components';
import Navigation from '../Navigation';
const Wrapper = styled.div`...`;
const AppLayout = props => {
return (
<Wrapper>
<Navigation />
<main>{props.children}</main>
</Wrapper>
);
};
export default AppLayout;
Any ideas why this might be happening and how to fix it?
Thanks
I was able to solve my issue two ways
Using withRouter
import { withRouter } from 'next/router';
import TestComponent from '../../components/TestComponent';
import AppLayout from '../../components/styles/_AppLayout';
const Section = props => {
return <AppLayout>Hi {props.query.slug}</AppLayout>;
};
export default withRouter(Section);
and passing the query parameter as props via getInitialProps
const Section = ({slug}) => {
return <AppLayout>Hi {slug}</AppLayout>;
};
Section.getInitialProps = async ({ query }) => {
const { slug } = query;
return { slug };
};
export default Section;
The following method worked for me, I am using React Hooks with Context and I need to also use the nextJS route with it, so following configuration can be followed.
Note: If you are using GraphQL then that can be also wrapped around the final JSX in _app.js
_app.js:
import { withRouter } from "next/router";
BuilderProvider is here Context Provider
const InjectRouterContext = withRouter(({ router, children }) => {
return <BuilderProvider value={router}>{children}</BuilderProvider>;
});
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<InjectRouterContext>
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
</InjectRouterContext>
);
}
}
Now in the Page, here it is somepage.js:
import { useRouter } from "next/router";
const somepage = () => {
const router = useRouter();
const { id } = router.query;
return (//JSX Here);
}
somepage.getInitialProps = async ({ query }) => {
const { slug } = query;
return { slug };
};
export default somepage;