Reputation: 1969
I'm using next.js for rebuilding an app for server side rendering. I have a button that handles a search request.
In the old app, the handler was this one:
search = (event) => {
event.preventDefault();
history.push({
pathname: '/results',
state: {
pattern: this.state.searchText,
}
});
}
In the results class, I could get the state date with this.props.location.state.pattern.
So now I'm using next.js:
import Router, { withRouter } from 'next/router'
performSearch = (event) => {
event.preventDefault();
Router.push({ pathname: '/results', state: { pattern: this.state.searchText } });
};
In the results class, I use
static async getInitialProps({req}) {
return req.params;
}
I'm not sure if I have to add this to my server.js:
server.get('/results', (req, res) => {
return app.render(req, res, '/results', req.params)
})
However, the function getInitialProps throws an error because req is undefined. Long text, short question: how to pass state or params to another page without using GET parameters?
Upvotes: 87
Views: 256909
Reputation: 3104
The approach to this has already been updated, for those who are using Next.js > v13.
Instead of passing an object into router.push
we would instead just pass a queryString
.
Now you would use useRouter
together with useSearchParams
The documentation here actually has a very good example
'use client'
export default function ExampleClientComponent() {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
// Get a new searchParams string by merging the current
// searchParams with a provided key/value pair
const createQueryString = useCallback(
(name: string, value: string) => {
const params = new URLSearchParams(searchParams.toString())
params.set(name, value)
return params.toString()
},
[searchParams]
);
return (
<>
<p>Sort By</p>
<button
onClick={() => {
// <pathname>?sort=asc
router.push(pathname + '?' + createQueryString('sort', 'asc'))
}}
>
ASC
</button>
{/* OR using <Link> */}
<Link
href={
// <pathname>?sort=desc
pathname + '?' + createQueryString('sort', 'desc')
}
>
DESC
</Link>
</>
);
}
Then on the receiving component/page you just use useSearchParams
export function SecondPage() {
const searchParams = useSearchParams();
const sortValue = searchParams.get('sort');
return <h1>Sorting by {sortValue}</h1>;
}
Upvotes: 1
Reputation: 1835
In Next.js 13 app directory, you can't pass the params like the previous answers, there is no way to do this using Next.js navigation system. however, you can use plain javascript to do this by using history.pushState(state, "", url)
you can read more about it here.
Below is an example of how to use it.
First page:
"use client";
import { useRouter, usePathname } from "next/navigation";
export default function First() {
const router = useRouter();
const pathname = usePathname();
function handleClick() {
history.pushState({ email: "[email protected]" }, "", pathname + "/second");
router.push("second");
}
return <button onClick={handleClick}>Navigate to Second page</button>;
}
Second page:
"use client";
import { useEffect, useState } from "react";
const myState = history.state;//store the state variable outside the component
export default function Second() {
const [routeState, setRouteState] = useState({});
useEffect(() => {
setRouteState(myState);
}, []);
return <h1>{routeState.email}</h1>;
}
Note: this approach will only work in client components and the state will disappear once you refresh the browser, so the use cases of this approach will be very limited. If you want a more convenient way to pass the data you can use query params or localstorage
Upvotes: 6
Reputation: 71
If you're using the App Router features and conventions that were introduced in Next.js 13, most of the previous answers to this question do not apply or work at all. For instance, the pathname string has been removed and replaced by usePathname(), and the query object has been removed and replaced by useSearchParams().
This page has the answers you're looking for: https://nextjs.org/docs/app/api-reference/functions/use-router
Upvotes: 1
Reputation: 1094
I would like to add in @Ahmet Firat Keler answer. If you want make your URL to remain clean and pass the data as well, we can do it using "next/link"
.
as
props works fine with next/link
and you can hide query parameters with next/link
as well.
<Link href={`/blogs/${item.slug}?id=${item.id}`} as={`/blogs/${item.slug}`} passHref>
<a href="" className="hover:text-cyanBlue">
Read More
</a>
</Link>
But keep in mind, this won't work if you set target="_blank"
to anchor tag or open link to the next tab of the browser
Upvotes: 2
Reputation: 966
I don't know whether this supports SSR, but I had to do it as follows to avoid the error cannot read property 'query' of undefined
.
This uses useRouter
hook to get access to the url, imported as below.
import { useRouter } from 'next/router'
Assume you want to pass data {name:'Someone'}
from Component A
to Component B
.
In Component A
,
const router = useRouter();
router.push(
{ pathname: "/path_of_component_b", query: { name: "Someone" } },
"path_of_component_b"
);
In Component B
,
const router = useRouter();
useEffect(() => {
alert(router.query.name); // Alerts 'Someone'
}, [router.query]);
Upvotes: 21
Reputation: 4065
If you want your url remain clean, make a small addition to Prithwee Das's answer like below.
Router.push({
pathname: '/about',
query: { name: 'Someone' }
}, '/about');
Now you can access props in your component using props
...
const YourComponent = (props) => {
useEffect(() => {
console.log(props.router.query.name);
}, [props.router.query]);
return (
<React.Fragment>
...
</React.Fragment>
);
};
...
Upvotes: 44
Reputation: 984
If you want 'clean' urls, one way to go about it is to add onClick handler to your link and store required information in context/redux store. It easy to implement if you already have one.
<Link href='...'>
<a onClick={()=>{dispatch(....)}}>Link<a/>
<Link>
Upvotes: 9
Reputation: 5246
In next.js
you can pass query parameters like this
Router.push({
pathname: '/about',
query: { name: 'Someone' }
})
and then in your next page (here in /about
page), retrieve the query
via the router
props, which needs to be injected to Component
by using withRouter
.
import { withRouter } from 'next/router'
class About extends React.Component {
// your Component implementation
// retrieve them like this
// this.props.router.query.name
}
export default withRouter(About)
Upvotes: 125