406

I'd like to display a title in <AppBar /> that is somehow passed in from the current route.

In React Router v4, how would <AppBar /> be able to get the current route passed into it's title prop?

  <Router basename='/app'>
    <main>
      <Menu active={menu} close={this.closeMenu} />
      <Overlay active={menu} onClick={this.closeMenu} />
      <AppBar handleMenuIcon={this.handleMenuIcon} title='Test' />
      <Route path='/customers' component={Customers} />
    </main>
  </Router>

Is there a way to pass a custom title from a custom prop on <Route />?

Raphael Rafatpanah
  • 19,082
  • 25
  • 92
  • 158
  • Possible duplicate of [How to get current route in react-router 2.0.0-rc5](https://stackoverflow.com/questions/35031911/how-to-get-current-route-in-react-router-2-0-0-rc5) – Damjan Pavlica Feb 18 '18 at 21:14

10 Answers10

473

In the 5.1 release of react-router there is a hook called useLocation, which returns the current location object. This might useful any time you need to know the current URL.

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

function HeaderView() {
  const location = useLocation();
  console.log(location.pathname);
  return <span>Path : {location.pathname}</span>
}

Community
  • 1
  • 1
joy08
  • 9,004
  • 8
  • 38
  • 73
  • 64
    Please note this can only be used inside the Router DOM (i.e. chid components, not in the class / functional component where the Router is used). It may be obvious but not to a newbie like me:-) I was getting all the time the error "useContext is undefined" – BennyHilarious May 23 '20 at 22:58
  • 1
    also this will not work if a router `redirect` was used. this will read the path before the redirect – Sonic Soul Jun 12 '20 at 13:16
  • 3
    why not make location a `const` instead of a `let` since we know it won't change in this context? – Mark Rogers Sep 18 '20 at 16:14
  • great for unit test compatibility, avoid mocking window.location – Oscar Nov 24 '20 at 15:25
  • 3
    They specifically asked for "React Router ***v4***", not v5. – eriegz Mar 17 '22 at 15:59
  • This gives location with variables included, not the original `path="X"`? Or maybe it was changed in v6? If so I may need to downgrade. – Annan Yearian Sep 09 '22 at 10:44
  • 2
    @eriegz that's true but this is also the first Google result when searching for "Get current path name react router" so it's a very good thing that this answer is shown at the top – ICW Nov 29 '22 at 16:03
251

In react router 4 the current route is in - this.props.location.pathname. Just get this.props and verify. If you still do not see location.pathname then you should use the decorator withRouter.

This might look something like this:

import {withRouter} from 'react-router-dom';

const SomeComponent = withRouter(props => <MyComponent {...props}/>);

class MyComponent extends React.Component {
  SomeMethod () {
    const {pathname} = this.props.location;
  }
}
Con Posidielov
  • 2,537
  • 2
  • 11
  • 4
  • 14
    please note that this is not always true: with react-router4 , if your component is rendered on a higher level respect to some nested routes (which extends the path later) the location.pathname inside WithRouter will be different from `window.location.pathname` – maioman Sep 16 '17 at 13:09
  • 4
    How do we get it programmatically outside of a React component? – trusktr Mar 07 '19 at 02:53
  • 2
    This solution doesn't provide how to use these props in the component holding the itself. – freesoul Nov 26 '20 at 13:22
91

If you are using react's templates, where the end of your react file looks like this: export default SomeComponent you need to use the higher-order component (often referred to as an "HOC"), withRouter.

First, you'll need to import withRouter like so:

import {withRouter} from 'react-router-dom';

Next, you'll want to use withRouter. You can do this by change your component's export. It's likely you want to change from export default ComponentName to export default withRouter(ComponentName).

Then you can get the route (and other information) from props. Specifically, location, match, and history. The code to spit out the pathname would be:

console.log(this.props.location.pathname);

A good writeup with additional information is available here: https://reacttraining.com/react-router/core/guides/philosophy

lowcrawler
  • 6,777
  • 9
  • 37
  • 79
82

There's a hook called useLocation in react-router v5, no need for HOC or other stuff, it's very succinctly and convenient.

import { useLocation } from 'react-router-dom';

const ExampleComponent: React.FC = () => {
  const location = useLocation();  

  return (
    <Router basename='/app'>
      <main>
        <AppBar handleMenuIcon={this.handleMenuIcon} title={location.pathname} />
      </main>
    </Router>
  );
}
Alexander Kim
  • 17,304
  • 23
  • 100
  • 157
36

Here is a solution using history Read more

import { createBrowserHistory } from "history";

const history = createBrowserHistory()

inside Router

<Router>
   {history.location.pathname}
</Router>
ravibagul91
  • 20,072
  • 5
  • 36
  • 59
Wael Bettayeb
  • 486
  • 4
  • 7
  • 5
    For those of us on the react functional path, this answer makes the most sense. Those `this.props....` whatever is just noise to our ears. – KhoPhi Nov 25 '19 at 15:03
  • This is the only solution that worked directly inside tags, without a child component or using the document/window location directly. – freesoul Nov 26 '20 at 14:06
36

Has Con Posidielov said, the current route is present in this.props.location.pathname.

But if you want to match a more specific field like a key (or a name), you may use matchPath to find the original route reference.

import { matchPath } from `react-router`

const routes = [{
  key: 'page1'
  exact: true,
  path: '/page1/:someparam/',
  component: Page1,
},
{
  exact: true,
  key: 'page2',
  path: '/page2',
  component: Page2,
},
]

const currentRoute = routes.find(
  route => matchPath(this.props.location.pathname, route)
)

console.log(`My current route key is : ${currentRoute.key}`)
Rasta_boy
  • 609
  • 7
  • 7
  • I have been able to use this method with v6, changing it to `matchPath(route.path, this.props.location.pathname)` as explained [there](https://stackoverflow.com/a/69887731/815290) – Walid Feb 11 '22 at 21:24
  • Use `matchPath(route, this.props.location.pathname)` to match the whole route definition – Tires Jan 15 '23 at 10:51
12

I think the author's of React Router (v4) just added that withRouter HOC to appease certain users. However, I believe the better approach is to just use render prop and make a simple PropsRoute component that passes those props. This is easier to test as you it doesn't "connect" the component like withRouter does. Have a bunch of nested components wrapped in withRouter and it's not going to be fun. Another benefit is you can also use this pass through whatever props you want to the Route. Here's the simple example using render prop. (pretty much the exact example from their website https://reacttraining.com/react-router/web/api/Route/render-func) (src/components/routes/props-route)

import React from 'react';
import { Route } from 'react-router';

export const PropsRoute = ({ component: Component, ...props }) => (
  <Route
    { ...props }
    render={ renderProps => (<Component { ...renderProps } { ...props } />) }
  />
);

export default PropsRoute;

usage: (notice to get the route params (match.params) you can just use this component and those will be passed for you)

import React from 'react';
import PropsRoute from 'src/components/routes/props-route';

export const someComponent = props => (<PropsRoute component={ Profile } />);

also notice that you could pass whatever extra props you want this way too

<PropsRoute isFetching={ isFetchingProfile } title="User Profile" component={ Profile } />
hal9000
  • 129
  • 1
  • 2
  • 4
    Is there any way we could turn this solution into a codepen? I want to use the more correct solution but I really don't understand how to implement. –  Apr 19 '19 at 00:24
5

Add

import {withRouter} from 'react-router-dom';

Then change your component export

export default withRouter(ComponentName)

Then you can access the route directly within the component itself (without touching anything else in your project) using:

window.location.pathname

Tested March 2020 with: "version": "5.1.2"

joy08
  • 9,004
  • 8
  • 38
  • 73
Siobhan
  • 67
  • 1
  • 2
  • 3
    Not sure about this one. Sure, it's giving the current pathname, but that doesn't change if I navigate to a new page. – alex Apr 05 '20 at 22:22
1

React Router Version 6

<Link to="/myuser?page=10#myHash">User</Link>

Use useLocation hook to get location object
const location = useLocation();

console.log('hash', location.hash); // #myHash
console.log('pathname', location.pathname); // /myuser
console.log('search', location.search); // ?page=10
Avnish Jayaswal
  • 161
  • 1
  • 4
0

1. First Warp App Component

// index.js

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

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
       <App />
    </BrowserRouter>
  </React.StrictMode>
);

2. Import useLocation Hook and get path name

// App.js

import {Routes, useLocation  } from "react-router-dom";

function App() {
  const location = useLocation();

  // Get current path
  const path = location.pathname;

  return (
      <>
       <Routes>
         <Components currentPath={path} />
       </Routes>
      </>
  );
}

location.pathname returns path name, use it as required.

Shah Fahad
  • 61
  • 3