Next.js: Possible to pass state to next/router?

Created on 15 Jan 2017  ·  34Comments  ·  Source: vercel/next.js

With react-router I was able to do:

browserHistory.push({ pathname: "/", state: { message: 'This is a message forwarded in a state.' } })

Is it possible to do something like this using next/router or a way to redirect the user and also pass some value over to the new page?

Most helpful comment

Same here, would be great if it will be possible pass data with Router.push() and retrieve it later with withRouter

All 34 comments

Currently that's not possible and I don't think we'll support it immediate future.

But let's open this and see whether we really really need this.

I think you should do this by passing query parameters.

I mean you can achieve a similar thing by passing in query parameters like nkzawa said, but I'd rather not pollute my the url with http://www.example.com/?message=This%20is%20a%20long%20message%20forwarded%20to%20be%20displayed and would rather have a state transfer like how react-router does it.

You can use as to disguise the URL

Well I suppose so, but if I were to use as, the pathname doesn't retain the actual pathname in props.url.pathname, which means more things to pass into the query. It's just _cleaner_ to have it pass the state.

I'm porting over a project to next.js and haven't run into any major compatibility problems since I found ways to refactor codes to make it work, it's just inconvenience and verbosity at this point that can be improved and all this issue is.

Thanks all for your input.

Closing this cause of inactivity 👍

A little over a year since I brought this up, but is this still not supportable?

You can save any required state in localStorage, sessionStorage, a variable, a Redux store, etc. and then use it in getInitialProps (checking you are running client side).

i think nextjs should start supporting react-router

I want same functionality.

Earlier I was using CRA and there I used to send state to routed component. I wants same functionality with nextjs.

What @sergiodxa suggested in workaround but library support will be good.

Same here, would be great if it will be possible pass data with Router.push() and retrieve it later with withRouter

I want same functionality. Any update on this ?

I want same functionality. Any update on this ?

me too

Another question related to this issue is:

  • I don't want to pollute my URL when I call the Router.push() and I want to pass a state to the next component. Is there any way to do it? Using localStorage or cookie is a bad practice as they are not directly controlled by React hooks or the old React lifecycle

I have a scenario where I have a clickable component. clicking it would open its details page. With current next.js i can pass the projects id and then get the details using useEffect and axios call but since i already have the data i really wished i could send the state to that page.

Would be nice to have this.

@sergiodxa Yes, there are many ways to pass temporary messages but the advantage of having it tied to the router is that we don't have to write extra code to manage the life cycle of the values we pass around. They will be tied to router navigation events and unavailable in other contexts.

For example, If I push it to my redux store, then I have to exclude it from being persisted to local storage and also dispatch a clear message action on the receiving end.

If I add it the query string it becomes a perma link that uses can bookmark and later return to.

But it I can push it to the next page and only the next page via router.push I don't have to make any compensations; the value will only be available in that context.

Very similar to connect-flash

No solution since Jan 15 2017 ?
We need that feature :

Same here, would be great if it will be possible pass data with Router.push() and retrieve it later with withRouter

Would be nice to have this in nextjs

if you want to hide query params, just use like this

Router.push(`/main?userName=${userName}`, 'main')

than the main page, you can see only /main on url and
console.log(Router.route) shows query

pathname: "/main"
query: {userName: "fadsfasd"}
asPath: "main"

oh yeah, that's true. Btw I find it really awkward that router requires two strings. react-router works beautifully without, why does this?

For those who want to make it, you can use Context Api.

Next.js provides the router.push() passing shallow: true as a prop.
It's the most simple state management to do that.
https://nextjs.org/docs/api-reference/next/router#routerpush

Willing to reconsider this, however it needs a great proposal on how to prevent users from shooting themselves in the foot using history state given you can't access history state server-side for example, it would be very easy to cause hydration issues.

Do note that re-opening this does not mean that I'm not going to write a RFC for this feature, that would be up to the people that want to have this feature.

Router.push({ pathname: '/', query: { message: 'This is a message forwarded in a state.' } }, '/')

More than 2 years and still waiting for state feature

Router.push({ pathname: '/', query: { message: 'This is a message forwarded in a state.' } }, '/')

This is still not internal state, it's a query string with a mask feature, which is quite an odd thing to do in my opinion.

I'm not super familiar with React ecosystem. But it appears that you can do

router.push(
  { pathname: '/hello-world' }, 
  '/hello-world/2', 
  { step: 2 }
);

When you go back and check before PopState, the option prop will contain { step: 2 }.

We only need this in the router object.

I'm not super familiar with React ecosystem. But it appears that you can do

router.push(
  { pathname: '/hello-world' }, 
  '/hello-world/2', 
  { step: 2 }
);

When you go back and check before PopState, the option prop will contain { step: 2 }.

We only need this in the router object.

It seams like another temporal hack, not intentional behavior. Expected options are listed in the docs. But something similar to this would be great to have as expected behavior

@likerRr Apparently all of the options parameter is being passed to window.history.state. So with my example:
window.history.state == { step: 2 }

@likerRr Apparently all of the options parameter is being passed to window.history.state. So with my example:
window.history.state == { step: 2 }

Seems like it is. Anyway, until it's documented, it can't be used in prod, because implementation of passing options can be changed anytime :disappointed: Another problem (?) with history state, that it's persistent. And if you play with "back"/"forth" buttons you will mostly get unexpected behavior.

As far as I understand the use case of what community wants is to pass data which will leave only during transition from one page to another and we don't have to bother of clearing it. And this data should not appear again when user clicks "back/forth" in a browser. Otherwise this is the best proposition (imo).

Would be nice if next js considered this

This worked for me, you can use
https://github.com/vercel/next.js/issues/771#issuecomment-612018764

1: in the Subscription page:
const handleClick = useCallback((mount) => {
Router.push(/payment?mount=${mount}, '/payment');
}, []);
2: in Payment Page
useEffect(() => {
const {
query: { mount },
} = Router;
!mount && Router.push('/campaign-overview/subscription');
console.log('PaymentVM:React.FC -> mount', mount);
}, []);

you can see value of mount in console browser.

I understand the issue and the convenience of being able to pass along state in router.push.

Would the following be a temporary solution?

Use the browser's history.pushState, as well as a local useState of a location string, and when we want to redirect, we use history.pushState as well as setting a new value to local location state. An update to the location-string-state should trigger a useEffect run. Then have a JS swich statment which evaluates the location and returns components based on the location. And if we wanna get to the same component without history.pushState (for exp. if the user refreshes the page), we can make the location a dynamic next query param. -- did not try it, just trying to think of workarounds.

For those who want to make it, you can use Context Api.

Next.js provides the router.push() passing shallow: true as a prop.
It's the most simple state management to do that.
https://nextjs.org/docs/api-reference/next/router#routerpush

What if in my in my getServerSideProps, I make two calls, one of which should be redone for every load, and one should only be loaded with a condition. For that, Shallow: true would not help much because its not a state manager, its either redo getServerSideProps, or don't do it at all.
An example of this scenario would be if I make two seperate calls in getServerSideProps. One for the main content of the page and then another call to get the navigation links. In an initial render, I want both calls to be on the server, but then, I already have the nav links in memory so I dont need to refetch them. Thats why we need state.

The only solution is to send along a as option with hidden query params but our code would be awful it for every <Link/> we pass in a bounch of query params that contains our current state. (Actually, as Im writing, Im thinking of making an HOC Link which should go the the specified href and send along a query object with the current state so I wouldnt need to write the state object in each <Linke/>, I'll only handle this in the HOC)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

irrigator picture irrigator  ·  3Comments

renatorib picture renatorib  ·  3Comments

swrdfish picture swrdfish  ·  3Comments

sospedra picture sospedra  ·  3Comments

jesselee34 picture jesselee34  ·  3Comments