Using regex in react router path prop to conditionally render components - reactjs

There may be a better solution here than using regex, but not sure how to go about it.
The issue is that I want my navigation component that lives in a component called MainLayout to show on all routes except on /login & `/logout
Currently, I have the following 3 routes
<Route exact path="/logout" component={Logout} />
<Route exact path="/login" component={Login} />
<Route
exact
path="/:subdirectory?/:nested?/:id?/"
component={MainLayout}
/>
So navigating to /login or /logout will render either Login or Logout and also MainLayout which is understandable with the current setup.
However, is there a way to use regex (or any other means) to check that if /:subdirectory is either /login or /logout then do not render component?

Related

Redirecting to subpage with id

I've had two routes:
<Route path="/client/:id/members" component={Members} />
<Route path="/client/:id/members/:mid" component={MemberProfile} />
why when I'm trigger:
window.location.href = `/client/${id}/members/${mid}`;
then my url is changed to correct form like in the route path but not redirect me to MemberProfile component?
Thanks for any help!
as
<Route path="/client/:id/members" component={Members} />
declared before
<Route path="/client/:id/members/:mid" component={MemberProfile} />
and
/client/${id}/members/${mid}
fit
"/client/:id/members"
Members component will still be rendered.
Consider one of the following:
decleare MemberProfile before Members
change MembersProfile route to /client/:id/member/:mid for example
use exact Route property
Given:
<Route path="/client/:id/members" component={Members} />
<Route path="/client/:id/members/:mid" component={MemberProfile} />
It seems like you are rendering these routes into a Switch component. Remember that the Switch component renders the first child <Route> or <Redirect> that matches the location. This means that route path order and specificity matters.
Order your routes by decreasing specificity. "/client/:id/members/:mid" is more specific than "/client/:id/members" and should render higher in the Switch.
<Switch>
...
<Route path="/client/:id/members/:mid" component={MemberProfile} />
<Route path="/client/:id/members" component={Members} />
...
</Switch>
Additional note
You may want to avoid using window.location.href to redirect as this reloads the entire page, and thus, your app. Use a Redirect component to render a declarative navigation, or use history.replace(`/client/${id}/members/${mid}`); to issue an imperative redirect.

React Router: Wrapping some Routes with a component and not directly inside Switch

I'm trying to do something like this
<Switch>
<SomeNavBar>
<Route path="page1">Page 1</Route>
<Route path="page2">Page 2</Route>
<Route path="page3">Page 3</Route>
</SomeNavBar>
<OtherNavBar>
<Route path="admin">Admin Page</Route>
</OtherNavBar>
</Switch>
Where I have wrapper component for a routes that are not the admin page.
However the admin route does not render Admin Page it just renders a blank page. The other routes work fine.
Is there a way to achieve this behavior?
There's a couple of issues with your example not related to the question which you should rectify before anything else.
The first is that the direct children of a Switch must always be a Route or Redirect - it doesn't know what to do with any other element and will just render the first thing it sees (in your case, the SomeNavBar component). The second is that path declarations must be prepended with a slash for the router to build them correctly, so /page1 and /admin for example.
With that out the way, here is a somewhat contrived example of how to get the behaviour you are after. For the pages, we are checking from a list of possible fragments before rendering SomeNavBar and the correct route. Notice also the exact parameter - this is so we don't also match paths that only begin with the specificed fragment, like /page1foo:
<Switch>
<Route exact path={['/page1', '/page2', '/page3']}>
<SomeNavBar>
<Route path="/page1">Page 1</Route>
<Route path="/page2">Page 2</Route>
<Route path="/page3">Page 3</Route>
</SomeNavBar>
</Route>
<Route path="/admin">
<OtherNavBar>
Admin Page
</OtherNavBar>
</Route>
</Switch>

How to tell google bot that page not found in React?

I have a React App with Routers, I also have 404 component, etc.
But I don't know how to send 404 header to google bot.
I'mm just thinking that it's not possible due React app without SSR.
Am I right?
If you are using Router, you can set your pages like this:
<Router>
<Switch>
<Route exact path = "/home" component={HomePage} />
<Route exact path = "/sign-up" component={SignUpPage} />
<Route exact path = "/login" component={LoginPage} />
<Route exact path="/incorrect-login" component={IncorrectLoginPage} />
<Route exact path = "*" component={PageNotFound} /> //404 Component
</Switch>
</Router>
With this, you set your PageNotFound to the bottom of your router list where if the url of the React App does not correspond to any of your previous urls, then the PageNotFound route is triggered. You can just render your not found component under that page like you would for any other page in your application.
I also used exact so that the url must be exactly the same along with a Switch statement so that only a SINGLE page component can be triggered at once. The * basically just means ALL other urls besides those specified previously.
The PageNotFound is treated as kind of like a default catch statement so it's at the bottom

React Router ignores my PrivateRoute wrapper when navigating using a Link

I'm having a strange issue with React Router. My PrivateRoute wrapper doesn't do its thing when navigating using a Link or NavLink.
Essentially I have something like this:
<BrowserRouter>
<Switch>
<Route exact path="/"><Home /></Route>
<PrivateRoute exact path="/private"><Private /></PrivateRoute>
</Switch>
</BrowserRouter>
PrivateRoute is just a wrapper around Route that checks for authentication.
Now, if I go to /private by typing it in the address bar, PrivateRoute does its job (and redirects to /login, but that doesn't matter).
However, if I use a NavLink in the Home component which has to="/private", React Router routes to the private route even if the user is unauthenticated.
Is there any way I can resolve this reasonably? And why does React Router behave like this and doesn't "go through" all the routes in BrowserRouter each time you navigate using a NavLink?
To solve your problem, you need to add exact or exact="true" on public Route.
If you don't include exact="true", <Route path="/"> refers all sub routes starting with /.
So /private will match / route hence it will render <Home /> component.
Here is updated code
<BrowserRouter>
<Switch>
<Route path="/" exact>
<Home />
</Route>
<PrivateRoute path="/private">
<Private />
</PrivateRoute>
</Switch>
</BrowserRouter>
Here is sample code
Well, this was a quite simple and dumb fix actually.
The problem was that the PrivateRoute component didn't "remount" when changing routes using Links (that is interesting and somehow clever behavior of React Router, I can imagine this improves performance).
Meanwhile, typing a URL into the address bar refreshes the entire page, thus "remounting" all components.
Since the logic for checking auth was in componentDidMount only, it didn't launch if the component wasn't "remounted", therefore creating my issue.
For any possible future visitors, to fix this problem, just move your auth checking logic from componentDidMount somewhere else, and reference it both in componentDidMount and componentDidUpdate. Don't forget to check if props actually changed in componentDidUpdate — otherwise you'll create an infinite loop — like so:
componentDidUpdate(prevProps, prevState) {
// You could also use shallowCompare, but that wasn't needed in my case
if (this.props.requiredPerms !== prevProps.requiredPerms) {
this.checkAuth(); // method with the logic which was in componentDidMount before
}
}

React router dom params issue

I tried to Routing the params ":id" in react with a sub Route ":id/history" and the route link not render the component on clicking
<Switch>
<Route path="/patients/:id" exact component={GeneralData} />
<Route path="/patients/:id/history" component={History} />
</Switch>
The Switch component renders the first route that matches the URL you entered
Because you are using a wildcard for your GeneralData Route like so
<Route path="/patients/:id" component={GeneralData}/>
No matter what you enter after /patients, it gets captured in that wildcard definition of that Route because it accepts literally anything. So even if you navigate to /patients/4834834/history it still satisfies the GeneralData route which was found first in the list of routes.
To fix this, simply move your History Route above your GeneralData Route. This makes it so the GeneralData route will not get rendered for anything that just satisfies /patients/:id. Switch will look to see if your URL matches History first.
<Switch>
<Route path="/patients/:id/history" component={History} />
<Route path="/patients/:id" component={GeneralData} />
</Switch>
I think you're omitting exact param.

Resources