Is it possible to define hash route in next.js?
Asked Answered
G

3

19

I had already made a modal component with <HashRouter> in react-router that became active and inactive with hash url i.e modals is inactive when url is /route and modal1 is active when url is /route#modal1. There is any ways to define hash routes in next.js?

Gravitate answered 3/2, 2020 at 9:49 Comment(5)
what were your attempts? are you using next.js with custom server?Pimental
I didn't find anything in next.js document to define hash routes. Yes, I'm using next.js with custom server.Gravitate
and with which server? express?Pimental
My server is express.Gravitate
You could probably use React Router with hash-based routing on a single Next.js page. I'm going to do this for a new SaaS product that shouldn't server-side render pages (except for a loading state) that don't need SEO because they're accessible only via login. I don't see this clashing with the Next.js router as React Router would unmount and deactivate when navigating to another Next.js page.Jin
P
17

The part of the url starting with the hash symbol (that identifies an html entity) is never sent to the server, so you cant match the url serverside (if the browser loads /route#modal1 the server will load /route) what you can do is :

Option 1 Handle the modal rendering client side, using next/router in your component with something like this :
(im assuming you are using class components)

  import Router from 'next/router'

  ....

  componentDidMount(){
    let id = Router.asPath.match(/#([a-z0-9]+)/gi )
    if(id){
      // i will show the modal
    }else{
      // something else
    }
  }

Option 2 Pass the id to the url without #.
In your server.js add a route similar to this :

  server.get('/route/:id?', (req, res) => {
    let {id} =  req.params 
    return app.render(req, res, '/mypage', { id})
  })

And then grab the id, ex. in getInitialProps

  static async getInitialProps (context) {
    let ctx  = context.query;
    return ctx
  }

And handle the modal

  componentDidMount(){
    let {id} =  this.props    
    if(id){
      // i will show the modal
    }else{
      // something else
    }
  }
Pimental answered 3/2, 2020 at 13:37 Comment(1)
Hey @Nico, Can you post another answer here for NextJs13+ (appRouter) please?Skinhead
C
5

You can use next/router to accomplish that.

In our case we use hash routing on a specific page to render different components depending on the hash url, so the user can go back and forth using regular web navigations buttons

// page.js

export default function MyPage() {
  const router = useRouter();
  const hash = router.asPath.split('#')[1] || '';
  const showModal = hash === 'modal1' ? true : false;
  const openModal = () => {
    router.push({ hash: 'modal1' });
  }  
  return (
    <>
      <h1>MyPage</h1>
      <Button onClick={openModal}>Open Modal 🙂</Button>
      {showModal && <ModalOne />}
    </>
  )
}
// ModalOne.js

export default function ModelOne {
  const router = useRouter();
  const closeModal = () => {
    router.push({ hash: '' });
  }
  return (
    <>
        <h1>Hello Modal</h1>
        <Button onClick={closeModal}>Close Modal 🙃</Button>
    </>
  )
}

Every time the router hash changes a re render is triggered, opening the modal in a similar way to what you would expect on a SPA

This also has the added benefit of closing the modal when pressing back on a mobile device, as it was in our use case expectations.

Note: I'm using nextjs version 12.1.0

Clarissa answered 8/9, 2022 at 19:30 Comment(0)
H
4

You can add a hash using the next/router.

Some pages I change the component that renders based on a state string, so to make sure I know which route I'm on (and keep the back button working) I add a state string stage as a hash to the URL when it detects a change.

React.useEffect(() => {
  router.push(`/booking#${stage}`)
}, [stage])

This will only work client side though.

Hartzog answered 7/7, 2021 at 18:33 Comment(1)
this solution fails when using router.push by passing in { pathname: '...url', query: '...query' }Abominable

© 2022 - 2024 — McMap. All rights reserved.