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 ofreact-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:
- Route component as
this.props.match
- Route render as ({ match }) => ()
- Route children as ({ match }) => ()
- withRouter as this.props.match
- 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
Compare 2 Arrays Which Returns Difference
Contain Form Within a Bootstrap Popover
How to Create a Hash or Dictionary Object in JavaScript
Where Should Ajax Request Be Made in Flux App
How to Read a Text File from Server Using JavaScript
Creating an Array of Cumulative Sum in JavaScript
Is It a Good Idea to Learn JavaScript Before Learning Jquery
What Does the @ Symbol Do in JavaScript Imports
Multiple Conditions for JavaScript .Includes() Method
Stop Cursor from Jumping to End of Input Field in JavaScript Replace
How to Add a Class to a Dom Element in JavaScript
How to Join Two JavaScript Objects, Without Using Jquery
Is 'Window' Really Global in JavaScript
Wrapping a Set of Dom Elements Using JavaScript
How to Persist a Es6 Map in Localstorage (Or Elsewhere)
Remove Characters from a String