Previously, I was using react-router-dom. With react-router-dom, I could define a route with query params like this:
<Route path="/p:productId" element={<Products />} /> // localhost:3000/p1 will match this route
But it seems like react-location doesn't work in the same way. The only way that I found is by defining the query params as a child of another route, but this leads to a slash before the actual letter 'p'.
The following example comes from the official documentation, but I'll rewrite it to match our own example.
const routes = [
{
path: 'p',
children: [
{
path: ':productId', // matches /p/:productId . localhost:3000/p/1 will match this route.
},
],
},
]
Is it possible to make it like the first example, which comes from react-router-dom?
Regardless of the answer, is it a bad practice to do it like the first example?
Related
I use react-router-config package from here: https://www.npmjs.com/package/react-router-config for my project. I created a Routes.js file where I set my routes configurations, it looks like this:
export default [
{
...App,
routes: [
{
...IndexPage,
path: '/',
exact: true
},
{
...CategoryPage,
path: '/computers'
},
{
...CategoryPage,
path: '/home'
},
{
...NotFoundPage
}
]
}
];
as you can see I use two paths '/computers' and '/home' to load the same component CategoryPage. I wonder if it possible to pass multiple paths in one object to load the same component, something like this:
{
...CategoryPage,
path: ['/computers','/home']
}
base on the documentation https://github.com/ReactTraining/react-router/blob/v3/docs/Glossary.md#path
path type is a string but when I read this update, I guess it's support for react router version 4.4
[https://reacttraining.com/react-router/web/api/Route/path-string-string][1]
In this example
<Route path={["/users/:id", "/profile/:id"]} component={User} />
For some reason, I think the way you wrote might be the way. You could first create your ideal structure, ex.
{
components: [...CategoryPage],
path: ['/computers','/home']
}
And then use your own utility function to transform it into your final structure. This way you can make your routing structure as flexible as you want and one source of data at the same time. I found thinking this way is more scalable than bending the routing default structure.
According to the accepted answer to this question, React Router 4 doesn't match query parameters anymore. If I go from a URL matched by one of my <Route>s to the same URL with a different query string, the content doesn't seem to change. I believe this is because navigating between URLs that match the same <Route> doesn't change the content, but please correct me if I'm wrong. Given this, how do I use React Router for a set of URL's that need to differ only by query parameter?
For example, many search engines and other sites that use search bars, including the site I am working on, use a query parameter, commonly q or query. The user may search for one thing, then decide that is not what he/she wants and search for another thing. The user may type in the second URL or search with the search bar again. There isn't really a place for the search term in the URL path, so it kind of needs to go in the query string. How do we handle this situation?
Is there a way, with React Router, to link to a URL that only differs in the query string and change the content, without refreshing the entire page? Preferably, this wouldn't require any external library besides React and React Router.
Try the render function prop instead of component prop of Route. Something like this:
<Route render={props => {
// look for some param in the query string...
const useComponentA = queryStringContains('A');
if(useComponentA) {
return <ComponentA {...props}/>;
} else {
return <ComponentB {...props}/>;
}
}}/>
There are 2 ways to do that:
1) Use location.search in react component to get the query string, then pass it to child component to prevent re-rendering the whole component. React-router has the official example about this.
2) Define a regex path of router to catch the query string, then pass it to react component. Take pagination as an example:
routes.js, for router config you can refer this
const routerConfig = [
{
path: '/foo',
component: 'Foo',
},
{
path: '/student/listing:pageNumber(\\?page=.*)?',
component: 'Student'
},
Student.js
render() {
// get the page number from react router's match params
let currentPageNumber = 1;
// Defensive checking, if the query param is missing, use default number.
if (this.props.match.params.pageNumber) {
// the match param will return the whole query string,
// so we can get the number from the string before using it.
currentPageNumber = this.props.match.params.pageNumber.split('?page=').pop();
}
return <div>
student listing content ...
<Pagination pageNumber = {currentPageNumber}>
</div>
}
Pagination.js
render() {
return <div> current page number is {this.props.pageNumber} </div>
}
The 2nd solution is longer but more flexible. One of the use cases is server sider rendering:
Apart from the react components, the rest of the application (e.g. preloaded saga) need to know the url including query string to make API call.
This Stack Overflow question/answer explains how to define React Router (v4) routes which contain multiple optional parameter, eg.:
<Route path="/to/page/:pathParam1?/:pathParam2?" component={MyPage} />
However, it doesn't explain how to put optional text in-between those parameters, for instance:
<Route path="/to/page/:pathParam1?/otherParam/:pathParam2?" component={MyPage} />
// Should match /to/page/1 AND /to/page/1/otherParam/2
This was certainly possible in previous versions of React Router, but I can't see how to do it in the current version. Is there any way to specify optional parameter/non-parameter pairings, or even just optional non-parameters? Something like:
<Route path="/to/page/:pathParam1?/(otherParam/:pathParam2?)" component={MyPage} />
React router uses path-to-regexp - https://github.com/pillarjs/path-to-regexp
You can match optional non-parameters with a path like this:
const path = "/to/page/:pathParam1?/(otherParam)?/:pathParam2?"
And to test it:
const re = pathToRegexp(path)
console.log(re.exec("/to/page/1"))
// ["/to/page/1", "1", undefined, undefined]
console.log(re.exec("/to/page/1/otherParam/2"))
// ["/to/page/1/otherParam/2", "1", "otherParam", "2"]
I have to access value to optional param(s) form a react router (React Router v4). Now problem is as we have avoid param(s) sequence.
For example as per following react router code we have to access pathPraram2 without define pathPram1 :
<Route path="/to/page/:pathParam1?/:pathParam2?" component={MyPage} />
You can use withRouter hoc from the react-router-dom (or from native router).
This will pass some routing props to your component.
Validate it with flow if you want to:
type PropType = {
match: {
params: {
pathParam1?: string, // '?' to emphasize its optional
pathParam2?: string,
},
},
};
In your component you can use them by simply checking for their existence.
if (this.props.params && this.props.params.pathParam1) {
// do something
}
I hope this helps.
withRouter: https://reacttraining.com/react-router/native/api/withRouter
Also, extending on #Shubham's answer, I recommend having these optional params with identifiers.
Example:
http://example.com/page/identifier-1/param-1/identifier-2/param-2
http://example.com/page/identifier-2/param-2
http://example.com/page
This way you can define a route based on page, and in the component you can check based on identifier the param your route contains.
For a route with params like such:
{
articleId: 'abc',
commentId: 'xyz'
}
To create a route mentioned above:
<Route path="/page/:key1?/:value1?/:key2?/:value2?" component={MyPage} />
Now to access these in component:
if (!this.props.match || !this.props.match.params) {
return;
}
let articleId = null;
let commentId = null;
if (
this.props.match.params.key1 &&
this.props.match.params.value1
) {
if (this.props.match.params.key1 === 'articleId') {
articleId = this.props.match.params.value1;
}
if (this.props.match.params.key1 === 'commentId') {
commentId = this.props.match.params.value1;
}
}
if (
this.props.match.params.key2 &&
this.props.match.params.value2
) {
if (this.props.match.params.key2 === 'articleId') {
articleId = this.props.match.params.value2;
}
if (this.props.match.params.key2 === 'commentId') {
commentId = this.props.match.params.value2;
}
}
then just simple check if articleId or commentId is null or not.
I think this will lead to a better url formation, though it increases conditions inside the component to get the parameters.
However in Shubham's answer, you will have less conditions and a different url formation. It's upon you to decide which one is preferable for you to use as per your use case.
Hope it helps.
It isn't directly possible for the Router to have an optional path param directly before the other
Consider the case
<Route path="/to/page/:pathParam1?/:pathParam2?" component={MyPage} />
Now say you wish to have pathParam1 and not pathParam2, so your route path will be
/to/page/pathpage1
Now consider another case when the pathParam1 is not passed but pathParam2 is, so route path looks like
/to/page//pathpage2
Now here pathParam1 will match as empty whereas the pathParam2 will match to pathpage2 which will work and you can access it like this.props.match.pathparam2
however it not clean in terms of the url as it contains two //. As better way would be to introduce a fixed path in between the params
<Route path="/to/page(/:pathParam1?)/somepath(/:pathParam2)?" component={MyPage} />
I am trying to do something with React Router and I can't seem to find a way to do it. I am using React Router 4.2.0.
I have some routes that looks like this:
<ConnectedRouter history={history}>
<div>
<Route exact path="/" component={Projects}/>
<Route path="/editor/:path" component={Editor}/>
</div>
</ConnectedRouter>
When I am on the page /editor, I would like to get the path argument with all the text that is put after even if it has '/' in it.
So if I am going to the page /editor/one/two path argument will be one/two.
If I am going to the page /editor/one/two/three path argument will be one/two/three.
Does anyone know if it is possible to do it ?
Thanks.
React router uses path-to-regexp for path matching.
Checking the path-to-regexp docs, you see that the library offers the option to match one-to-many parameters with a + prefix:
var re = pathToRegexp('/:foo+')
// keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
re.exec('/bar/baz')
//=> ['/bar/baz', 'bar/baz']
In other words, /editor/:path+ matches /editor/one/two/three, and argument path would be one/two/three.