React-Router Getting This.Props.Location in Child Components

react-router getting this.props.location in child components

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
}

react-router-dom: getting props.location from within BrowserRouter component

You can also do it using withRouter which has a similar result to putting the code in a render parameter and avoids the need for a "fake" <Route/>.

Essentially you put the JSX that needs to know the location in a component of its own, which is wrapped by withRouter. This supplies the location to the component:

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

const Content = withRouter(props =>
<div className={(props.location.pathname === "/account") ? "backg...
...
</div>
);

Then you use that in your main router section:

class App extends Component{
render() {
return (
<BrowserRouter>
<Content/>
...

Can't access this.props.location from react-router Link

The render function gets the route props (match, location, history) as a single object parameter.

One fix would be to just use those:

<Route 
path="/loosePath"
render={(routeProps) => <Component2 someProps={props} {...routeProps} />}
></Route>

Here we destructure the routeProps passed in as props to Component2. This way you can pass both custom props and the route props to your component.


However, the recommended way would be to just pass Component2 as a child:

<Route 
path="/loosePath"
>
<Component2 someProps={props} />
</Route>

Doing it this way will not add the route props to it like in the render, component, or children function methods. Instead, you would utilize withRouter for accessing route props in a class component, or the available hooks from within functional components.

For example, if Component2 were a functional component, you would get the location like this:

const Component2 = (props) => {
let location = useLocation();
...

Or as a class component, you would simply wrap the exported component with withRouter:

class Component2 extends Component {
render() {
this.props.location
...

export default withRouter(Component2)

react-router - Cannot get information in this.props.location

You need to pass the router props into the component since you're using the render prop of the <Route/> component.

Also, In your App component you don't need BrowserRouter as Router since you're already wrapping <App/> in index.js. I changed the import and removed the wrapping <Router/> component.

import { Route, Switch } from 'react-router-dom';

class App extends React.Component {
...
render() {
if (this.state.auth) {
return (
<Switch>
...
<Route path="/editUser" render={props =>
<EditUser {...props} className="App" app={this}/>
}/>
</Switch>
);
}
}
}

this.props.location.state is undefined in React Link Router

Issues

  • You are using the low-level Router which needs a history object to have a defined location object to work with.
  • The code is linking to a new window, so the app is loaded/mounted from scratch and the passed route state isn't transferred.

To address the undefined location you have a couple options:

  1. Import a custom history creator from the history package:

    import { createBrowserHistory } from 'history';

    const history = createBrowserHistory();

    ...

    <Router history={history}>
    ...
    </Router>
  2. Use one of the higer-level routers, i.e. BrowserRouter, HashRouter, MemoryRouter, etc...:

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

    ...

    <Router>
    ...
    </Router>

To address accessing the "state" in the receiving component you'll need to add a bit of logic. When the app is started in a new window/tab the state isn't transferred, so to combat this you can send the route state serialized as a queryString search param.

<Link
className={"link-styling"}
target="_blank"
rel="noreferrer"
to={{
pathname: this.state.pathName,
search:
"stuff=content&moreStuff=moreContent" + // existing search params
"&dataPassed=This is the passed data.", // additional for state
state: { dataPassed: "This is the passed data." }
}}
>
Click Me
</Link>

And then in ExamplePage process the queryString to extract and delete the added "dataPassed" query param, and redirect with populated route state previously existing queryString.

class ExamplePage extends Component {
componentDidMount() {
const { history, location } = this.props;
const { pathname, state, search } = location;

console.log({ location });

const searchParams = new URLSearchParams(search);
let dataPassed;

if (searchParams.has("dataPassed")) {
dataPassed = searchParams.get("dataPassed");
searchParams.delete("dataPassed");
}
history.replace({
pathname,
search: searchParams.toString(),
state: { dataPassed }
});
}

render() {
return (
...
);
}
}

Edit this-props-location-state-is-undefined-in-react-link-router

props.location is undefined with route component

Issue(s)

  1. react-router-dom v6 Route components rendered via the element prop don't receive route props.
  2. Route children components must use react hooks to access the route context, i.e. useParams, useLocation, useNavigate, etc... and therefore must be function components.
  3. The console.log calls are in the function body so these are unintentional side-effects. This is likely why they are called twice, assuming the app is being rendered into a React.StrictMode component.

Solution

Challenges should use the uselocation hook to access the pathname. Move the console logs into an useEffect hook so they are called once per render to the DOM.

const Challenges = (props) => {
const { pathname } = useLocation();

useEffect(() => {
console.log(++a);
console.log(pathname);
});

const path = pathname;
const slug = path.split("/").slice(path.split("/").length - 1)[0];
const challenge = challenges.find((challenge) => challenge.slug === slug);

return (
<div>
<h1>30 Days Of React Challenge</h1>
<ul>
{challenges.map(({ name, slug }) => (
<li key={name}>
<NavLink to={`/challenges/${slug}`}>{name}</NavLink>
</li>
))}
</ul>
<Routes>
<Route
path="/challenges"
element={<h1>Choose any of the challenges</h1>}
/>

<Route path={path} element={<Challenge challenge={challenge} />} />
</Routes>
</div>
);
};

v6 api-reference

React Router - passing location prop through function in Route

React Router DOM automatically passes match location and history props.

You can use the route render prop to pass them manually if you wish:

<Route path="/:url" render={(routeProps) => <ConfirmAccount DIR_URL={url} {...routeProps} />} />

Getting location prop in the component where BrowserRouter is initialized

While rendering the components using a render method, you need to pass on the Router props to the component being rendered like

   <Route
path="/p"
render={(props) => {
return (
<Layout {...props}>
<P/>
</Layout>
);
}}
/>
<Route
path="/v"
render={(props) => {
return (
<Layout {...props}>
<V/>
</Layout>
);
}}
/>


Related Topics



Leave a reply



Submit