React-router: Modal base on route

Created on 9 May 2015  Â·  17Comments  Â·  Source: ReactTraining/react-router

So basically what I am trying to achieve is the Pinterest style modal page for their pins. Whichever page you are on, when you click on a pin a modal with the pin details pops up, and the page where you are from still sit in the background. The url in the address bar changes so you can link to the pin from other sites or share it to your friends. And when you close the pin modal you go back to previous page.

Is react-router supporting this kind of routing?

Most helpful comment

Probably worth noting here that when looking at the source for the pinterest example be sure to check the code for the exact version of react-router you are using.

The example in master currently passes through the Link state as follows:

<Link
  key={picture.id}
  to={{
    pathname: `/pictures/${picture.id}`,
    state: { modal: true, returnTo: this.props.location.pathname }
  }}
  >

Is 1.0.3 to must be a string and thus passing through state should be achieved like this:

<Link
  key={picture.id}
  to={`/pictures/${picture.id}`}
  state={{ modal: true, returnTo: this.props.location.pathname }}
  >

All 17 comments

I want to know too! Can anyone help?

Thanks!

Just do everything normal and create the modal (with $replaceThisWithYourFavoriteModalLibrary) in componentDidMount and/or open it in componentWillReceiveProps later. You may also just apply a class to your "detail" component that will set position:fixed to the detail container and apply propper formatting however your modal should look like.

Rough Example:

componentDidMount() {
      const modalContainer = this.refs.modalContainer.getDOMNode();
      YourLibrary.createModal(modalContainer);
 }
render() {
   return <div className='modal' ref='modalContainer'/>
}

The problem is, when you get to the render() function through url routing, the 'previous page' is already gone, no way to pull it back and make it 'sit on the background'.

Anyway, after a couple days effort I believe this kind of routing is not in favour of the library's philosophy, where (I think) it is believed that url should mean a solid state of the app, so whenever a user hits a url, exact same content should be shown.

So if you believe otherwise, you might need to look somewhere else for solution.

I've been wanting to support this for a while and we do now in 1.0!

Check out the pinterest example on master.

Nice

I still see it as incomplete. Although its nearly perfect, it seems that on refresh, even if you arrive on the same URL with the modal, the modal will not trigger. Which kind of makes sense based on the architecture. But maybe you guys have an idea?

Example:
example.com/modal => shows modal

  1. Click a Link to=example.com/modal => shows modal
  2. Refresh => no modal, content is rendered in page instead.

Probably worth noting here that when looking at the source for the pinterest example be sure to check the code for the exact version of react-router you are using.

The example in master currently passes through the Link state as follows:

<Link
  key={picture.id}
  to={{
    pathname: `/pictures/${picture.id}`,
    state: { modal: true, returnTo: this.props.location.pathname }
  }}
  >

Is 1.0.3 to must be a string and thus passing through state should be achieved like this:

<Link
  key={picture.id}
  to={`/pictures/${picture.id}`}
  state={{ modal: true, returnTo: this.props.location.pathname }}
  >

+1 on @andreigabreanu comment

What kind of modals libraries is everyone dealing with? I'm finding the react-overlays library from the react-bootstrap folks works when I navigate to a route: https://github.com/react-bootstrap/react-overlays

I'm using react-modal and so far it has done the job well.
On Thu, 31 Dec 2015 at 16:35 Tim Dorr [email protected] wrote:

What kind of modals libraries is everyone dealing with? I'm finding the
react-overlays library from the react-bootstrap folks works when I navigate
to a route: https://github.com/react-bootstrap/react-overlays

—
Reply to this email directly or view it on GitHub
https://github.com/rackt/react-router/issues/1172#issuecomment-168205046
.

Don't mean to resurrect an old issue but I think this got closed a bit prematurely. I'm trying to implement this now based on the Pinterest example outlined by @ryanflorence and I'm running up against the same issue that @andreigabreanu describes. On refresh, this completely breaks down and the modal content is rendered into the page instead.

Has there been any headway on this at all in the current version of react-router?

For what it's worth, I'm using my own Modal component but it works in much the same way other React modal components work, really.

The Pinterest example seems to have two flaws: 1. there is no "back" support (i.e. previousChildren isn't preserved when navigating from a modal to another modal) and 2. like @reintroducing said, when navigating initially to the modal route, there is no background. Is there a simple way to implement it that I'm missing?

There is no modal route. That's the point – it's one route that depends on how you get there. Note that on Pinterest itself, refreshing when you've popped up the modal for a pin will also drop the modal, just as in the bundled example.

refreshing when you've popped up the modal ... will also drop the modal

That's exactly the issue were talking about. While some things are just fine showing in their own page, that's not always desireable.

(For example, some sites link directly to example.com/login when advertising their site. It's a bit silly though to bring a user to a site and show them only the login page. Hence, it's desirable to have the sites default route (or whatever) rendered underneath.)

It would be great if there were a simple way to say "render this route WITHOUT removing the last route", and a way to specify a default route if there is no previous route.

@mbrevda could you just handle that yourself in your root route component? If you want to render both the current route _and_ the previous route, store the root component's children (the child route) prop in your state and do your own logic to determine whether to render the children from props/state/both.

Perhaps not the best solution but we do something similar w/ our use of react-router on www.treesnetwork.com and it solves our problem.

could you just handle that yourself in your root route component?

Pretty sure I could. I was hoping, based on my needs and the many other requests here, that there could be an official solution.

For anyone who stumbles across this issue trying to achieve parity with Twitter/Pinterest modals, here are a few things to note. The examples ([v2] and [v4]) don't cover everything needed to achieve parity:

  • History state used to enable/disable the modal—like in the examples—will be persisted across page reloads. Twitter/Pinterest do not behave like this—they switch to the permalink view on reload. This can be worked around by calling router.replace to clear the state before the main app component enters (e.g. onEnter).
  • On Twitter/Pinterest, exiting the modal will navigate the browser back to the route shown prior to the modal entering (rollback)—for example, if I close the modal, I can go forward in my history to see the modal again.
    ~I achieved this by keeping a count of location changes: https://github.com/ReactTraining/history/issues/334#issuecomment-322740342.~ I dived into the Twitter source code to work out how they were doing this. This is what I saw:
    js this.rollback = function(t, e) { e.rollbackCount > 0 ? (this.isRollback = !0, history.go(-e.rollbackCount)) : delete this.isRollback }
    They set rollbackCount as location state when calling history.pushState. The same could be achieved by providing state to the Link component.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

andrewpillar picture andrewpillar  Â·  3Comments

maier-stefan picture maier-stefan  Â·  3Comments

Waquo picture Waquo  Â·  3Comments

ackvf picture ackvf  Â·  3Comments

ryansobol picture ryansobol  Â·  3Comments