Same route path with different component in React - reactjs

I need a View component and an Edit component. Depends on conditions, a button needs to go View page or Edit page.
I set a Route like below.
The problem is the paths are the same.
<Route exact path='/users/:user_id' component={Users.Edit} />
<Route exact path='/users/:user_id' component={Users.View} />
In page, I have links like below
(type = "A") ? <Link to="users/1">view</Link> : <Link to="users/1">edit</Link>
For now, the router has same path so the button goes to the Edit component.
Is there any good react way I can call Edit component or View component?
or Do I need to just like below?
<Route exact path='/users/:user_id' component={Users.Edit} />
<Route exact path='/users/:user_id/view' component={Users.View} />

I think this is the right decision
<Route exact path='/users/:user_id' component={Users.Edit} />
<Route exact path='/users/:user_id/view' component={Users.View} />
But usual practice for CRUD to define routes in this way
<Route exact path='/users/' component={Users.List} />
<Route exact path='/users/create' component={Users.Create} />
<Route exact path='/users/:user_id' component={Users.View} />
<Route exact path='/users/edit/:user_id' component={Users.Edit} />

You should do it like you suggest with the /view suffix, but I would suggest combining the /users/:user_id with the Users.View component, and the /users/:user_id/edit with the Users.Edit component.
The reason 1 exact url cannot be handled based on conditions is when you open that url from let's say an e-mail, there is no way of telling which component to render.
There is a way, but it's harder than adding just 2 routes.
You might want to change the view/edit decision to a query param on 1 route, but then you have to create a new wrapper component around Users.Edit and Users.View to handle the decision based on the query param. So your route should look like
<Route exact path='/users/:user_id' component={Users.EditOrViewDecision} />
Next you can create links to that route by passing search to the Link
<Link to={{
pathname: '/users/1',
search: '?view=edit'
}}/>
But this way you still have to manage your decision in the EditOrViewDecision based on the ?view=edit query which component you want to display.

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.

Ensuring component re-initialization when route params change

I have the following routes defined:
<Switch>
<Route path="/" exact component={HomePage} />
<Route path="/project/:id/search" component={SearchPage} />
<Route path="/project/:id/upload" component={UploadPage} />
</Switch>
The issue is that search results (local state of the SearchPage component) remain when you navigate to another project's search page. I could solve it by manually clearing state in willReceiveProps when the ID changes but I want to avoid that as there are several sub-pages of /project that would need the logic.
Using render={()=> <SearchPage />} made no difference.
What's a clean way of ensuring that my components get re-initialized when the parameter in the URL changes?
You may use 'key reset state' technique: if special prop key is different React will for sure recreate element instead of updating.
So it may be
<Route
path="/project/:id/search"
render={({ match: {params: {id} } })=> <SearchPage key={id} />}
/>
To me this affects readability in bad way. So using componentDidUpdate(willReceiveProps is deprecated) seems to be better maintainable.

Is it a bad practice to use Navbar on all the available routes in React?

I always use Navigation bar on all of my screens.
Is it a bad practice to use Navigation bar on all the available screens ?
It's always recommended for Reusability to have repeated code in a separate component, and then reuse that component, so that you don't duplicate code. If you want to change something in that component you only have to change it in one part, not everywhere.
If you want that all your routes include this component, add it before the router, so it is always included. For example like this:
render(){
<div>
<h1>test</h1>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/messages" component={Messages} />
<Route path="/about" component={About} />
</Switch>
</div>
}
So test will always render no matter what route you choose.
If what you want is to create a layout, for example for private routes where you only show the navbar for logged in users (which is the most common scenario), have a look at this answer in SO.

React Router render components with /:username or /component/

I am trying to implement a routing structure where a user goes to another user's page or their own when the path is /:username. I also want to render another page with a path /watch or /watch/ .. Facebook has a similar setup where /:username will take you to your page or another user's and /watch/ for example is a page. Is there best practice to achieve this with react-router?
As of now I have something like this..
<Route path="/" exact component={authenticated ? Home : Index} />
<Route path="/watch/" component={Watch} />
<Route path="/:username" exact component={({match}) => {
if(match.params.username === data.Username) {
return <ProfilePage match={match} />
} else {
return <UserPage match={match} />
}
}} />
Now if I got to /watch/ the profile component is being rendered aswell. So :username is going to match all my routes?
As you already deducted, /:username is matching at the same time as /watch/ because both patterns match the URL /watch/.
Thankfully, React Router provides a <Switch> component for cases like this one, where only the first match is rendered:
<Switch>
<Route path="/watch/" component={Watch} />
<Route path="/:username" component={...} />
</Switch>
Now, with the URL /watch/, only the first route is rendered, even though the second one matches too.
If you are using react-router-dom v6, do these:
instead of Switch, you should use Routes
instead of component={<SomeComponent />} property, use element={<SomeComponent />}
Just in case, you can Read this article about upgrading from v5 to v6

Reactjs - React Router disallowing paths

I have a route
<Route exact path="/view/:personID" component={PersonView} />
It works fine, however /view still renders, albeit with no person in it. Is there a way to disallow this path or turn in into a 404?
Answer was to use switch
<Switch>
<Route exact path="/view/:personID" component={PersonView} />
<Redirect from='/view' to='/' />
</Switch>
You can manage this on your component, in the render section test if you have your personID if not return a custom error/view.

Resources