AlvMF1
AlvMF1

Reputation: 170

How to redirect old react-router HashRouter (with the #) to BrowserRouter?

We're replacing react-router-doms HashRouter with BrowserRouter and would like to redirect old routes to the new ones. I tagged nginx because I don't mind making redirects there. :)

So say we have an old route /#/users and /#/users:id: They should match and redirect to /users and /users/:id.

So far I tried (react-router-dom v5.0.1):

<Router>
  <Switch>
    <Route path='/users' component={UsersComponent} />
    <Route path='/users/:id' component={UsersDashComponent} />
  </Switch>
  <Redirect from='/#/users' to '/users' />
  <Redirect from='/#/users/:id' to='/users/:id' />
</Router>

The first route matches and redirects fine. The second one (with the id) is problematic. When I navigate to /#/users/123 it redirects to /users/:id. It's replacing the actual 123 with :id.

Those are two examples of routes. We have more with params to redirect as well.

Upvotes: 7

Views: 15569

Answers (4)

Praveen Nagaraj
Praveen Nagaraj

Reputation: 33

export const history = createBrowserHistory();

export const App: FC = () => {
   return (
     <Router history={history}>
       <Switch>
        <Route path="/settings" exact component={Settings} />
       </Switch>
     </Router>
  );
};


export const Settings : FC = () => {
   return (
      <HashRouter basename="/" hashType="noslash">
        <Switch>
              <Route path="/profile">
                <Profile />
              </Route>
       </Switch>
    </HashRouter>
  );
};

 import {history} from "./App.tsx";

 export const Profile : FC = () => {
      return (
        <Router history={history}>
           <Link to="/product/1"/>
        </Router>
       );
    };

  // It's simple store your history in a variable and make use of it

Upvotes: 0

RecuencoJones
RecuencoJones

Reputation: 2887

To be honest, none of these solutions worked for me really, I wanted to perform a redirect from all my previous routes to the new ones without #.

While the accepted answer should be fine for most cases, I'm also handling 404s, which would not really be caught by such redirect.

Ended up adding a guard interacting with React Router history before rendering my switch:

function App() {
  const history = useHistory()

  if (location.hash.startsWith('#/')) {
    history.push(location.hash.replace('#', '')) // or history.replace
  }

  return (
    <Switch>
      <Route path="/" exact component={ Home } />
      ...
      <Route path="*" component={ PageNotFound } />
    </Switch>
  )
}

Upvotes: 6

AlvMF1
AlvMF1

Reputation: 170

Here's my solution:

<Router>
  <Switch>
    <Route path='/users' component={UsersComponent} />
    <Route path='/users/:id' component={UsersDashComponent} />
    <Route exact path='/' render={({ location }) => <Redirect to={location.hash.replace('#', '')} />} />
  </Switch>
</Router>

Only routes that have /# will match /. One could easily add a conditional if needed to render something on root.

Upvotes: 0

ravibagul91
ravibagul91

Reputation: 20765

I think for navigation you are using something like this,

<Link to="/#/users" />
<Link to="/#/users/123" />

As per docs,

A <Router> that uses the hash portion of the URL (i.e. window.location.hash) to keep your UI in sync with the URL.

When using HashRouter you don't need to prepend # manually React router automatically adds # in URL

So your routes must be,

import { HashRouter } from 'react-router-dom'


<HashRouter>
  <Switch>
    <Route exact path='/users' component={UsersComponent} />
    <Route exact path='/users/:id' component={UsersDashComponent} />
  </Switch>
</HashRouter>

And links should be,

<Link to="/users" />
<Link to="/users/123" />

Now coming to your question, how to replace HashRouter with BrowserRouter?

To do so you just need to do this,

import { BrowserRouter } from 'react-router-dom'


<BrowserRouter>
  <Switch>
    <Redirect from='/#/users' to '/users' />
    <Redirect from='/#users/:id' to='/users/:id' />
    <Route exact path='/users' component={UsersComponent} />
    <Route exact path='/users/:id' component={UsersDashComponent} />
  </Switch>
</BrowserRouter>

And your links should be same.

Note: Also have a look I have added exact to route, it will match the exact path.

Upvotes: 3

Related Questions