Get Path Params in React-Router V4

How to get params in component in react router dom v4?

I assume you are following the Redux tutorial on Egghead.io, as your example code seems to use what is defined in that video series. I also got stuck on this part trying to integrate React Router v4, but eventually found a working solution not far from what you have tried.

⚠️ NOTE: one thing I would check here is that you are using the
current version of react-router-dom (4.1.1 at the time of this
writing). I had some issues with optional filters in the params on
some of the alpha and beta versions of v4.

First, some of the answers here are incorrect, and you indeed can use optional params in React Router v4 without the need for regular expressions, multiple paths, archaic syntax, or using the <Switch> component.

<BrowserRouter>
<Route path="/:filter?" component={App} />
</BrowserRouter>

Second, as others have noted, React Router v4 no longer exposes params on route handler components, but instead gives us a match prop to use.

const App = ({ match }) => {
return (
<div>
<AddTodo />
<VisibleTodoList filter={match.params.filter || 'all'} />
<Footer />
</div>
)
}

From here, there are two ways to keep your content in sync with the current route: using mapStateToProps or using the HoC withRouter, both solutions are already talked about in the Egghead series so I won't recapitulate them here.

If you are still having trouble, I urge you to check out my repository of the completed application from that series.

  • Here is the commit using the mapStateToProps solution
  • Here is the commit using the withRouter soluiton

Both of which seem to work fine (I just tested both of them).

How to get all param in React Router v4

React router doesn't work that way. You set up a route with the params that you need and then 'this.props.match.params' gets all the params for you.

If you set a route like this:

<Route path="/:view" component={LayoutPage} />

You are only defining one param, so even if you call:

http://localhost:3000/type/article/myotherparam/andanotherparam/etc/etc2

You will only get type because the Route is only expecting the first param (defined as :view).

If you want to define multiple params you do:

<Route path="/:view/:param2/:param3" component={LayoutPage} />

This way you make sure you have 3 params for example.

Regex and handling unknown number of params

Now, since I suppose you don't know how many params are there going to be, you can use a regular expression to match all the params but you will need some parsing afterwards.

So, you can define your route as:

<Route path="/:view+" component={LayoutPage} />

Call it like this:

http://localhost:3000/type/article/myotherparam/andanotherparam/etc/etc2

and then if you log:

console.log(JSON.stringify(this.props.match.params));

You will get:

{"view":"type/article/myotherparam/andanotherparam/etc/etc2"} 

You can then split by /:

this.props.match.params.view.split('/')

And you will get the array of params:

["type","article","myotherparam","andanotherparam","etc","etc2"]

Get path params in react-router v4

In order to receive the path param in you component, you need to first connect your component with withRouter HOC from react-router so that you can access the Router props and get the path params from the match props as this.props.match.params.id

Sample Code:

import {withRouter} from 'react-router';

class BookDetailedView extends React.Component {
render() {
var id = this.props.match.params.id

}
}
export default withRouter(BookDetailedView) ;

or simply passing it with render prop in route as

<Route path="/details/:id" render={({match}) => (
<BookDetailedView
bookStateUpdated = {this.bookStateUpdated}
book = {this.state.books}
id={match.params.id}
/>
)}/>

From the React Documentation of match

match

A match object contains information about how a <Route path> matched
the URL. match objects contain the following properties:

  • params - (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path
  • isExact - (boolean) true if the entire URL was matched (no trailing characters)
  • path - (string) The path pattern used to match. Useful for building nested s
  • url - (string) The matched portion of the URL. Useful for building nested s

You’ll have access match objects in various places:

  1. Route component as this.props.match
  2. Route render as ({ match }) => ()
  3. Route children as ({ match }) => ()
  4. withRouter as this.props.match
  5. matchPath as the return value

If a Route does not have a path, and therefore always matches, you’ll
get the closest parent match. Same goes for withRouter

Passing parameters with react router v4 and using them in url's

Route component is passing parameters to the rendered component so when you check props of ProductPage component you will see match prop and it contains key named params. Here is an example https://codesandbox.io/s/1y773j6kk4

React router 4, path with parameter

As you can see in the snippet below it works as you wish.

Have you encapsulated the Switch component in a Router? (HashRouter or BrowserRouter) That seems to be the issue.

Even if I repeat the Home component on Product and click the same links the app behaves as it is supposed to. (btw don't repeat the Home component on the Product component it was a way to examplify stuff)

const Home = () => (  <ul>    <li><ReactRouterDOM.Link to='/'>Home</ReactRouterDOM.Link></li>    <li><ReactRouterDOM.Link to='/product/1'>Product 1 details</ReactRouterDOM.Link></li>    <li><ReactRouterDOM.Link to='/product/2'>Product 2 details</ReactRouterDOM.Link></li>  </ul>  );
const Product = props => ( <div> <Home /> <p>{props.match.params.number}</p> </div>);
const App = () => ( <ReactRouterDOM.HashRouter> <ReactRouterDOM.Switch> <ReactRouterDOM.Route exact path='/' component={Home}/> <ReactRouterDOM.Route path='/product/:number' component={Product}/> </ReactRouterDOM.Switch> </ReactRouterDOM.HashRouter>);
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script><script src="https://unpkg.com/react-router/umd/react-router.min.js"></script><script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>
<div id="root"></div>

How to get query parameters in react-router v4

The ability to parse query strings was taken out of V4 because there have been requests over the years to support different implementation. With that, the team decided it would be best for users to decide what that implementation looks like. We recommend importing a query string lib. Here's one that I use

const queryString = require('query-string');

const parsed = queryString.parse(props.location.search);

You can also use new URLSearchParams if you want something native and it works for your needs

const params = new URLSearchParams(props.location.search);
const foo = params.get('foo'); // bar

You can read more about the decision here

React Router v4 - How to get current route?

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

React Router v4 Nested match params not accessible at root level

Try utilizing query parameters ? to allow the parent and child to access the current selected topic. Unfortunately, you will need to use the module qs because react-router-dom doesn't automatically parse queries (react-router v3 does).

Working example: https://codesandbox.io/s/my1ljx40r9

URL is structured like a concatenated string:

topic?topic=props-v-state

Then you would add to the query with &:

/topics/topic?topic=optimization&category=pure-components&subcategory=shouldComponentUpdate

✔ Uses match for Route URL handling

✔ Doesn't use this.props.location.pathname (uses this.props.location.search)

✔ Uses qs to parse location.search

✔ Does not involve hacky approaches

Topics.js

import React from "react";
import { Link, Route } from "react-router-dom";
import qs from "qs";
import Topic from "./Topic";

export default ({ match, location }) => {
const { topic } = qs.parse(location.search, {
ignoreQueryPrefix: true
});

return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/topic?topic=rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/topic?topic=components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/topic?topic=props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<h2>
Topic ID param from Topic<strong>s</strong> Components
</h2>
<h3>{topic && topic}</h3>
<Route
path={`${match.url}/:topicId`}
render={props => <Topic {...props} topic={topic} />}
/>
<Route
exact
path={match.url}
render={() => <h3>Please select a topic.</h3>}
/>
</div>
);
};

Another approach would be to create a HOC that stores params to state and children update the parent's state when its params have changed.

URL is structured like a folder tree: /topics/rendering/optimization/pure-components/shouldComponentUpdate

Working example: https://codesandbox.io/s/9joknpm9jy

✔ Uses match for Route URL handling

✔ Doesn't use this.props.location.pathname

✔ Uses lodash for object to object comparison

✔ Does not involve hacky approaches

Topics.js

import map from "lodash/map";
import React, { Fragment, Component } from "react";
import NestedRoutes from "./NestedRoutes";
import Links from "./Links";
import createPath from "./createPath";

export default class Topics extends Component {
state = {
params: "",
paths: []
};

componentDidMount = () => {
const urlPaths = [
this.props.match.url,
":topicId",
":subcategory",
":item",
":lifecycles"
];
this.setState({ paths: createPath(urlPaths) });
};

handleUrlChange = params => this.setState({ params });

showParams = params =>
!params
? null
: map(params, name => <Fragment key={name}>{name} </Fragment>);

render = () => (
<div>
<h2>Topics</h2>
<Links match={this.props.match} />
<h2>
Topic ID param from Topic<strong>s</strong> Components
</h2>
<h3>{this.state.params && this.showParams(this.state.params)}</h3>
<NestedRoutes
handleUrlChange={this.handleUrlChange}
match={this.props.match}
paths={this.state.paths}
showParams={this.showParams}
/>
</div>
);
}

NestedRoutes.js

import map from "lodash/map";
import React, { Fragment } from "react";
import { Route } from "react-router-dom";
import Topic from "./Topic";

export default ({ handleUrlChange, match, paths, showParams }) => (
<Fragment>
{map(paths, path => (
<Route
exact
key={path}
path={path}
render={props => (
<Topic
{...props}
handleUrlChange={handleUrlChange}
showParams={showParams}
/>
)}
/>
))}
<Route
exact
path={match.url}
render={() => <h3>Please select a topic.</h3>}
/>
</Fragment>
);

How can I get the params from the url with React?

You can use withRouter for getting router information such as location, history, path, and params.

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

...

const VerifyAccount = withRouter(props) => {
const { token, email } = props.match.params;
console.log("toke, email: ", token, email) // And also show me how it looks!!!
...
}

And you should define your route like this.

<Route path='/verify-account/:token/:email' component={VerifyAccountPage} />

And you should call like this:

https://your-domain/verify-account/[token]/[email]

This will work.

React Router V4 - Can't get URL params in props

The match, location, and history props are passed into your render function.

Example:

<Route key="post" path="/post/:id" render={({ match }) => <Post name={match.params.name}/>} />

Documentation: https://reacttraining.com/react-router/web/api/Route/Route-props



Related Topics



Leave a reply



Submit