103

As I understand <Route path="/" component={App} /> will gives App routing-related props like location and params. If my App component has many nested child components, how do I get the child component to have access to these props without:

  • passing props from App
  • using window object
  • creating routes for nested child components

I thought this.context.router would have some information related to the routes, but this.context.router seems to only have some functions to manipulate the routes.

Community
  • 1
  • 1
xiaofan2406
  • 3,250
  • 5
  • 26
  • 34

2 Answers2

177

V6

You can use useNavigate, useLocation and useMatch in your component to get matchPath, navigate and location .

const Child = () => {
  const location = useLocation();
  const navigate = useNavigate();
  const match = useMatch("write-the-url-you-want-to-match-here");

  return (
    <div>{location.pathname}</div>
  )
}

export default Child

V5.1 & Hooks (Requires React >= 16.8)

You can use useHistory, useLocation and useRouteMatch in your component to get match, history and location .

const Child = () => {
  const location = useLocation();
  const history = useHistory();
  const match = useRouteMatch("write-the-url-you-want-to-match-here");

  return (
    <div>{location.pathname}</div>
  )
}

export default Child

V4 & V5

You can use withRouter HOC in order to inject match, history and location in your component props.

class Child extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return (
      <div>{location.pathname}</div>
    )
  }
}

export default withRouter(Child)

V3

You can use withRouter HOC in order to inject router, params, location, routes in your component props.

class Child extends React.Component {

  render() {
    const { router, params, location, routes } = this.props

    return (
      <div>{location.pathname}</div>
    )
  }
}

export default withRouter(Child)

Original answer

If you don't want to use the props, you can use the context as described in React Router documentation

First, you have to set up your childContextTypes and getChildContext

class App extends React.Component{
  
  getChildContext() {
    return {
      location: this.props.location
    }
  }

  render() {
    return <Child/>;
  }
}

App.childContextTypes = {
    location: React.PropTypes.object
}

Then, you will be able to access to the location object in your child components using the context like this

class Child extends React.Component{
   
   render() {
     return (
       <div>{this.context.location.pathname}</div>
     )
   }
   
}

Child.contextTypes = {
    location: React.PropTypes.object
 }
QoP
  • 27,388
  • 16
  • 74
  • 74
  • thanks for the pointer. I did not read that part of the documentation. I thought there is only ```context.router``` – xiaofan2406 May 30 '16 at 12:20
  • You ought to mention [if you want your application to be stable, don't use context. It is an experimental API and it is likely to break in future releases of React](https://facebook.github.io/react/docs/context.html#why-not-to-use-context). – Vinnie James Jan 22 '17 at 02:21
  • 3
    I'm new to React. Thus, forgive me if I'm wrong, but what's wrong with using `window.location.pathname`? – Artur Barseghyan Oct 23 '18 at 07:55
  • 1
    window.location is mutable so it's considered best practice not to access it, preferring to use an immutable version. Also, I think it's possible to use logical locations which differ from the window.location (at least this is true in nextjs) so it's possible to get a different location from your router than the direct window history – Chanoch Dec 21 '18 at 14:42
  • @ArturBarseghyan The `window` object doesn't exist if the React code is run on the server e.g. to implement server-side routing. – ChrisW Jun 18 '20 at 10:44
  • .what about V6? – Rony Tesler Jan 13 '22 at 14:13
  • The hooks don't seem to work for descendant components. – Drazen Bjelovuk Feb 17 '22 at 17:42
6

If the above solution didn't work for you, you can use import { withRouter } from 'react-router-dom';


Using this you can export your child class as -

class MyApp extends Component{
    // your code
}

export default withRouter(MyApp);

And your class with Router -

// your code
<Router>
      ...
      <Route path="/myapp" component={MyApp} />
      // or if you are sending additional fields
      <Route path="/myapp" component={() =><MyApp process={...} />} />
<Router>
skWyz
  • 154
  • 1
  • 10