React Router doesn't match all optional parameter - javascript

I'm facing a situation where I have my router working fine with the following configuration:
<Route path="/" component={Blog}>
<Route path="list(/:category)(/:subcat)" component={ArticleList} />
<Route name="article/:category(/:subcat)/:id" component={ArticlePage} />
</Route>
But now I was asked to improve the URL and remove some "unecessary" prefixes from the URLs
Current URL -> Desired URL
blog/list/football/worldcup -> blog/football/worldcup
blog/list/football -> blog/football
blog/article/football/10 -> blog/football/10
So I tried unsuccessfully to change my route to keep all parameters optional
<Route path="/" component={Blog}>
<Route path="(/:category)(/:subcat)" component={ArticleList} />
<Route name=":category(/:subcat)/:id" component={ArticlePage} />
</Route>
Is there a way to match the urls as described using react router?

You can simply have it like this
<Route path="blog" component={Blog}>
<IndexRoute component={ BlogComponent } />
<Route path=":category" component={ ArticleCategoryList } />
<Route path=":category/:subcat" component={ ArticleSubCategoryList } />
</Route>
I have prefixed blog to the route.
IndexRoute will match /blog route, it acts as the index route.
:category will match blog/football or blog/any-sport
:category/:subcat will match both blog/football/worldcup and blog/football/10
You will have to be careful here as this will match for both subcategory and id.
You can write a function/middleware which can validate the type of route.. whether id or subcategory.

Related

/path/:id not switching view when Link is to={"/path/" + slug}

I am trying to get a specific post appear by using its slug. I have sucessfully made this happen by setting the Route path to /journal:id and Link to={"/journal" + post.field.slug}. However this is not what I want the url to look like. Any guess why the Route won't recognize the added slash?
<Switch>
<Route path='/journal' component={Journal} />
<Route path='/journal/:id' component={SinglePost} />
<Route path='/shop' component={Shop} />
<Route path='/contact' component={Contact}/>
</Switch>
When I click on the Link inside of Journal that should display the SinglePost component, the URL changes but the view doesn't change and I still see the Journal. This is the Link:
<Link
className='posts__post'
key={post.fields.slug}
to={"/journal/" + post.fields.slug}
>
If you have multiple paths that have common parts like /journal and /journal/:id (common part is /journal) you should add attribute exact to shorter path to not stop searching for a route if only partially matched
<Switch>
<Route exact path='/journal' component={Journal} />
<Route path='/journal/:id' component={SinglePost} />
<Route path='/shop' component={Shop} />
<Route path='/contact' component={Contact}/>
</Switch>

Protecting a group of routes with React Router 4

playing around with protected routes in React Router 4 and wondering whether something that I've been able to get to work is even possible.
<Switch>
<Route exact path="/" component={LandingPage} />
<Route path="/sign-in" component={SignIn} />
<Route exact path="/auth/home" component={Home} />
<Route exact path="/auth/my-profile" component={UserProfile} />
<ProtectedRoute path="/auth" />
</Switch>
I have these routes as shown above and I have set up a protected route called /auth
What I want is to use this to protect any and all routes starting with /auth
So in this example both
<Route exact path="/auth/home" component={Home} />
<Route exact path="/auth/my-profile" component={UserProfile} />
Would also be protected routes.
Make sense?

Pass URL params in route - ReactJS

I have a URL
https://website.com/enable/code=react/string=true
My React router looks like this
<Router history={history}>
<Route
path="/"
component={App}
>
<IndexRoute component={Page1} />
<Route path="/enable/language='dynamicVal'/string='dynamicVal'>{page2()}</Route>
</Route>
</Router>
Now the Route path i need to get the dynamic value for language and string
I have tried this.
/enable/language=(/:react)/string=(/:true)
How and where to define the dynamic values?
You can go with the path param approach and structure your Routes like
<Router history={history}>
<Route
path="/"
component={App}
>
<IndexRoute component={Page1} />
<Route path="/enable/:language/:codeString'>{page2()}</Route>
</Route>
</Router>
and in your component you get get the path params like
this.props.params.language and this.props.params.codeString if you are using react-router-v3 or below
and
this.props.match.params.language and this.props.match.params.codeString if you are using react-router-v4
Assuming react-router v4 (not tested on v3, which is what you seem to be using?), you can define a Route as such:
<Route
exact path="/enable/language=:language/string=:stringVal"
component={YourComponent} />`
In YourComponent, both params will be available under this.props.match.params.language and this.props.match.params.stringVal, respectively.
See this CodeSandbox for a working example.

React Router - How to IndexRedirect to dynamic route

I have a situation in my React app to look like something as follows using react-router. I want the index of the users/:userId endpoint to redirect to another endpoint that includes a :userId params. What is a good way to do this? Right now the user from currentUser will return null because the code is only executed once in the beginning when the App is loaded the user is not yet authenticated. I'm guessing I will need to force react-router to reload the history and certain variables, or change the order of when I do authentication?
routes.js
{ /* Routes requiring login */ }
<Route onEnter={requireLogin}>
<Route path="users" component={Users}>
<Route path=":userId" component={User}>
<IndexRedirect to={`/users/${currentUser().id}/profile`} />
<Route path="profile" component={UserProfile} />
<Route path="settings" component={UserSettings} />
<Route path="activity" component={UserActivity} />
</Route>
</Route>
</Route>
If I understand it correctly and you want to redirect from /users/1 to /users/1/profile and /users/2 to /users/2/profile, you can simply replace ${currentUser().id} with :userId.
So your code would looks like this:
<Route onEnter={requireLogin}>
<Route path="users" component={Users}>
<Route path=":userId" component={User}>
<IndexRedirect to="profile" />
<Route path="profile" component={UserProfile} />
<Route path="settings" component={UserSettings} />
<Route path="activity" component={UserActivity} />
</Route>
</Route>
</Route>
Because the redirect is in the context of the route :userId: you can simply define your target route relative.

IndexRoute sub-routes

I have a web site with few ordinary pages and a page with Google Map. When map marker is clicked a panel with marker details is displayed next to the map. This detail has own URL so that users can link to it:
<Route path="/" component={App}>
<IndexRoute component={Welcome} />
<Route path="map" component={Map}>
{/* Detail is a child component of Map,
it only adds detail panel markup to Map. */}
<Route path="detail/:id" component={Detail} />
</Route>
<Route path="about" component={About} />
</Route>
This works fine. But let's get rid of Welcome page and display Map right on the web root so that:
/ renders App > Map components
/detail/:id renders App > Map > Detail components
/about renders App > About components
<Route path="/" component={App}>
{/* Map has to be IndexRoute so that it is displayed at root URL. */}
<IndexRoute component={Map}>
<Route path="detail/:id" component={Detail} />
</IndexRoute>
<Route path="about" component={About} />
</Route>
But this doesn't work because IndexRoute can't have subroutes.
This is the best solution I have found:
<Route path="/" component={App}>
<Route component={Map}>
<IndexRoute component={EmptyComponent} />
<Route path="detail/:id" compoent={Detail} />
</Route>
<Route path="about" component={About} />
</Route>
But I don't like the empty component.
Am I missing something? Am I doing something unusual? Why it is not possible to do it the first more intuitive way?
Move the / path
<Route component={App}>
<Route path="/" component={Map}>
<Route path="detail/:id" component={Detail}/>
</Route>
<Route path="/about"/>
</Route>
Your solution looks largely fine to me – the only caveat is that you don't need to specify the component in that case; just do <IndexRoute />.
By design, index routes terminate matching, but it's easy to insert trivial routes.
Maybe I am wrong but it seems as if your tried to set another route in:
<IndexRoute component={Map}>
<Route path="detail/:id" component={Detail} />
</IndexRoute>
So your basic structure is something like:
<IndexRoute>
<Route> </Route>
</IndexRoute>
According to your error it is not allowed that there is a <Route> inside of your <IndexRoute>... At the beginning you did not do that mistake because you closed the <IndexRoute> before you opened the next <Route>-Tag.
So if you want your code to work again you should not open another <Route> inside of your <IndexRoute>. You managed to fix this by adding an Dummy-IndexRoute. So if you want to set your Map component as IndexRoute you will have to change your HTML structure so that there is no Detail component inside of your map component because then you will have the same problem again that you got a <Route> inside your <IndexRoute>

Categories