I have a route with dynamic path, using params:
<Route
path="/main/:id"
element={
<Page />
}
/>
When I reach that page, using React Router useLocation, I'm able to get the full path:
"/main/5432gt34"
Is there a way to retrieve the path with the params name instead of the actual path?
(output I'm looking for is:)
"/main/:id"
I'm hoping this might be possible since React Router is aware of the params inside the path and you can extract those with useParams
I don't think react router gives a way to do this but you could do something like this if you're trying to find an easy solution.
<Route
path="/main"
element={
<Page type="index"/>
}
/>
<Route
path="/main/:id"
element={
<Page type="id"/>
}
/>
then handle the type parameter in your page component.
I doubt that it's possible but you can always just pass it as property.
<Route
path="/main/:id"
element={
<Page
path="/main/:id"
/>
}
/>
Aside from that answer for this is here: react-router v6: get path pattern for current route
Yes you can do it by using useParams only if you know the prefix (You're sure that the path starts with "/main" and the rest is dynamic as you mentioned in your question):
let params = useParams();
useEffect(() => {
let dynamicPath = "/main";
Object.keys(params).forEach((key) => {
dynamicPath += `/:${key}`;
});
console.log(dynamicPath);
}, []);
Solution 1: You could pull the id from the string using a regex.
var location = useLocation();
var myRegexp = /main\/(.*)/;
var id = myRegexp.exec(location.pathname)[1];
Little explanation of the regex:
\/ allows us to do match with "main/"
(.*) gives the rest of the match as a second result in returned array.
Once you have the id you can store it a reactContext so that it can be used in any child component.
Solution 2: useRouteLoaderData
This solution would require you to refactor your router so that it one of the data routers but afterwards you should be able to do:
const user = useRouteLoaderData("id");
Related
I am trying to know if it is possible or not to add the title of an article into the URL after redirecting to a specific article?
An example:
https://www.analyticsinsight.net/top-50-programming-languages-learn-coding/
so I am using reactjs with nodejs and MySQL.
I have a table with their columns, post_Text, post_Title, etc.
I only need to add the title of the article to the URL after User clicks on the title of a specific article.
i have a router as follows.
<Route path="/post/:id" exact>
<Post />
</Route>
and in the post.js file, I have a simple get method.
axios.get(`${server}/posts/byId/${id}`).then((res) => {
setPosts(res.data);
});
i would appreciate your help:_)
a well put question. I asked myself the same. Here is how I did it.
I set up the route, much like you have but with a second route that had another level of depth and another param on the end.
<Route path="/post/:id" exact><Post /></Route>
<Route path="/post/:id/:post_title" exact><Post /></Route>
On the click handler that navigates to the post, I did this. The values passed here. The regex simply identifies white spaces so that they can be replaced with a string.replace method.
const handleReadPost = (post_id, post_title) => {
const urlRegex = /\s/g;
const url_title = post_title.toLowerCase().replace(urlRegex, '-');
navigate(`/posts/${post_id}/${url_title}`);
};
In my case, it then just worked. I didn't need to make any adjustments to my Axios GET or logic in the Post component.
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.
Lets say we have two components for Post and Project. Each post and project has slug. I want to access post and projects by slug. So we have routes:
<Route path="/:post_slug" component={PostComponent} />
<Route path="/:project_slug" component={ProjectComponent} />
And for example when you visit some post pr project, an action gets called to fetch its data by params. Something like this:
this.props.fetchPost(this.props.match.params.post_slug)
this.props.fetchProject(this.props.match.params.project_slug)
If I do only one component accessible by slug only, then it works. But if I want to access two different components by slug, then it's messed up. And i.e. when I visit post, react thinks that I'm visiting project.
Maybe there is some way to handle such case in react-router-dom?
There is no way to do this, since the router can't differentiate between the two routes. For example, if I were to navigate to site.com/my_slug, the router wouldn't know whether my_slug is supposed to be a :post_slug or a :project_slug. It's sending you to a project when they're both present because it interprets them to be the same route and so it uses the last one you define.
An alternative you could try is being a bit more explicit with your routes, like so:
<Route path="/post/:post_slug" component={PostComponent} />
<Route path="/project/:project_slug" component={ProjectComponent} />
You could do this if you put the detection logic in another component, like this:
<Route path="/:any_slug" component={AnyComponent} />
Then let that component figure out what type of ID you have and render the desired sub-component accordingly:
const AnyComponent = props => {
if (slugIsProject(props.match.params.any_slug)) {
return <ProjectComponent id={props.match.params.any_slug} />;
} else {
return <PostComponent id={props.match.params.any_slug} />;
}
}
This way the router always renders the same component (AnyComponent) but that component appears differently depending on what the ID is determined to be.
Is it possible to have routes with different parameters and render different components based on the parameters?
For an example can I do:
<Route path="/SamePath/:param1" component={Component1} />
<Route path="/SamePath/:param2" component={Component2} />
If you are trying to have a the same route structure but render different components based on the value of the param, then you could try using render to decide which component to render based on the value of the param:
<Route path="/SamePath/:param1" render={ (props) => {
if (props.match.params.param1 == 'something') {
return <Component1 { ...props } />
} else {
return <Component2 { ...props } />
}
} />
If it is for lets say only two routes that will differ instead of using the capturing : just type in the name Eg.( samePath/organges samePath/apples) of the route if thats not the case and you want to capture a variarty range of to render differnt components you could use the regex routes feature of react router 4.. but that is much more complicated
In my project, I created a dictionary mapping possible values of the parameter to the desired component, and created <Route>s based on this dictionary.
<Switch>{
[{
['param1']: Component1,
['param2']: Component2,
}].forEach((component, param) =>
<Route
component={component}
exact
path={`/path/with/${param}`}
/>
)
}</Switch>
This will produces individual <Route>s for each path variation you wish to match. It will render different components for each route and, to me, seems in keeping with React-Router v4's dynamic routing ethos.
I encountered a problem: I couldn't access the value of the param via the match property passed to the rendered child. The Route matches against a specific path string (e.g. '/path/with/paramValue1) and not against a route descriptor with a parameter (e.g. '/path/with/:param'). This means thematch.params` dictionary passed to the child will not contain any keys or values. If you don't need the params in your child, this method will work fine. I wanted to inspect the param in the child so I had to look for a different method.
My client has specific SEO/URL requirements, I'm trying to figure out how to make this work with react-router.
How can a set of URLs matching the same pattern, be declared to use different Handlers?
e.g. /A is HandlerA but /B is HandlerB and /B/C is HandlerA also, where there are many permutations (dynamic at run-time) that must be catered for.
Assuming global RouteTable holds all the data needed to make the decision, it turns out this can be done in advance of the <Route> object being constructed:
var routes = RouteTable.map(r => {
if (some logic) {
return (<Route handler={A} name={r.url} path={r.url} />);
} else {
return (<Route handler={B} name={r.url} path={r.url} />);
}
});
var routes = (
<Route path='/'>
{routes}
</Route>
);
and then all <Links> are just done with URL, e.g. <Link to={url}>...