ChatGPT解决这个技术问题 Extra ChatGPT

React Router v4 - How to get current route?

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 />?


C
Community

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>
}


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"
also this will not work if a router redirect was used. this will read the path before the redirect
why not make location a const instead of a let since we know it won't change in this context?
great for unit test compatibility, avoid mocking window.location
They specifically asked for "React Router v4", not v5.
e
e382df99a7950919789725ceeec126

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;
  }
}

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
How do we get it programmatically outside of a React component?
This solution doesn't provide how to use these props in the component holding the itself.
l
lowcrawler

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


But how do you get the complete url?
A
Alexander Kim

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>
  );
}

This answer should be rated much higher. Using the hook is so much easier and intuitive than these other solutions (if on RR v5)
This is the current answer as of RR v5
r
ravibagul91

Here is a solution using history Read more

import { createBrowserHistory } from "history";

const history = createBrowserHistory()

inside Router

<Router>
   {history.location.pathname}
</Router>

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.
This is the only solution that worked directly inside tags, without a child component or using the document/window location directly.
R
Rasta_boy

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}`)

I have been able to use this method with v6, changing it to matchPath(route.path, this.props.location.pathname) as explained there
h
hal9000

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 } />

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.
j
joy08

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"


Not sure about this one. Sure, it's giving the current pathname, but that doesn't change if I navigate to a new page.