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 & V5You 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)
V3You 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 answerIf 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 thisclass 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 ahistory
object to have a definedlocation
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.
location
you have a couple options:Import a custom history creator from the
history
package:import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
...
<Router history={history}>
...
</Router>Use one of the higer-level routers, i.e.
BrowserRouter
,HashRouter
,MemoryRouter
, etc...:import { BrowserRouter as Router } from 'react-router-dom';
...
<Router>
...
</Router>
<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 (
...
);
}
}
props.location is undefined with route component
Issue(s)
- react-router-dom v6
Route
components rendered via theelement
prop don't receive route props. - Route children components must use react hooks to access the route context, i.e.
useParams
,useLocation
,useNavigate
, etc... and therefore must be function components. - 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 aReact.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
How to Call a Dynamically-Named Method in JavaScript
Event.Wheeldelta Returns Undefined
Uncaught Typeerror: Cannot Use 'In' Operator to Search for 'Length' In
Javascript: Unicode String to Hex
Finding "Line-Breaks" in Textarea That Is Word-Wrapping Arabic Text
Basic Ajax Send/Receive with Node.Js
React-Router Getting This.Props.Location in Child Components
Decompress Gzip and Zlib String in JavaScript
Angularjs Communication Between Directives
Throttle Amount of Promises Open at a Given Time
Detect 64-Bit or 32-Bit Windows from User Agent or JavaScript
Quickest Way to Pass Data to a Popup Window I Created Using Window.Open()
Object Doesn't Support This Property or Method Rails Windows 64Bit
Sending Binary Data in JavaScript Over Http
What Is the Point of Void Operator in JavaScript
Wait Till a Function with Animations Is Finished Until Running Another Function
JavaScript String and Number Conversion
How to Randomly Generate HTML Hex Color Codes Using JavaScript