I have a simple app where I try to interchange between 2 routes, and for each route there is a specific component to be rendered. Unfortunately, it seems like it remains stuck on the first Route I set inside the Switch.
Here you can access a sandbox containing the simplified app. I have set 2 NavLink components to manage the 2 routes.
in the builer component, you should use path instead to :
<Route path="/checkout" exact render={() => <div>Checkout</div>} />
<Route path="/" exact>
{this.state.showModal ? <div>Modal {orderSummary}</div> : null}
<div>Main Page</div>
{this.state.error ? errorMessage : ingredientControls}
</Route>
I tried it, it's work
Related
How can I conditionally render a nav bar in React Router 5?
so far I've got this in my <Router>
{window.location.href.includes('data-url') ? null : (
<CONNECTED_NAV />
)}
which does work but with one issue. I have a link in my data-url component which redirects back to the app. but once it redirects back and lands on another route /home then the nav bar is still not showing and I've consoled logged in the <Router> component and it's not re-rendering so that's why it's not showing.
is there a better way to force an update? or how to conditionally render a navbar?
If you want your navbar to show up on the /home page only then you have to specify a route:
<Route exact path="/home" component={CONNECTED_NAV} />
This way the navbar will be only visible when the URL matches /home
But if you want to show the navbar conditionaly on the homepage then you can also do that by replacing component with render
<Route exact path="/home" render={() => (condition ? <CONNECTED_NAV /> : null)} />
Route must be wrapped in BrowserRouter if you don't know about these maybe please visit
React Router
Just expanding on #ahmad-nawaz-khan solution
You may still want to pass in the router props from react-router
<Route exact path="/home" render={(routerProps) => (condition ? <CONNECTED_NAV {...routerProps} /> : null)} />
I want to route through 3 sites. Login - Dashboard - Details
Details is based on data selection in Dashboard.
If I refresh the url/Details site, the context is lost and i would like to redirect to Dashboard, but Details is throwing erros before i can redirect. How can I change this behaviour?
I've tried the following approaches without success:
1. redirection in the Browserrouter based on if the necessary data exists, if not redirect to Dashboard
2. Within Details componentWillMount() I have set up a redirect
Do I really need to check every data usage if data exists? This seems like quite a hassle for simple routing...
This is my routing configuration. The second redicrect doesn't work.
{this.props.token?<Redirect to="/dashboard" />:<Redirect to="/login" />}
{this.props.selectedCow?<Redirect to="/dashboard"/>:null}
<Switch>
<Route path="/login" component={Login} />
<Route path="/details" component={CowDetails} />
<Route path="/dashboard" exact component={Dashboard} />
</Switch>
Error: Data is not defined (CowDetails is rendered and context is missing before redirection)
I was using Redirect in the wrong way. As specified in the Docs it actually works without rendering the component.
https://reacttraining.com/react-router/web/api/Redirect
So for me it is
<Route exact path="/details" render={() => (
this.props.selectedCow ? (
{CowDetails}
) : (
<Redirect to="/dashboard"/>
)
)}/>
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
I have something like this using react-router 4:
<Route exact path="/" children={({match}) => (
<TransitionGroup component={firstChild}>
{match && <Home match={match} />}
</TransitionGroup>
)}/>
<Route exact path="/idea/:id" children={({match}) => (
<TransitionGroup component={firstChild}>
{match && <IdeaDetails match={match} />}
</TransitionGroup>
)}/>
<Redirect from='*' to='/' />
Basically if someone types in a url other than idea/:id, I want to redirect them back to the home page. When I run this code, it seems to do I expect. Except in the developer consoles, I see this warning
Warning: You tried to redirect to the same route you're currently on:
"/"
Is there a way to define the routes that I have without tripping this warning? Is there a way to tell react router to not process any subsequent route rules once one of them has been found?
Is there a way to tell react router to not process any subsequent route rules once one of them has been found?
Yes, you need to wrap your routes in a Switch component. When your routes are wrapped in a Switch, it finds the FIRST matching route and then returns it without continuing. Without a Switch, the router will return ALL routes that match the current url.
I am still learning react router v4. and I'd like to know what exactly is the difference between doing this
getting location using
const {
match,
location,
layoutBoxed,
navCollapsed,
navBehind,
fixedHeader,
sidebarWidth,
theme,
} = this.props;
Option 1
if(location.pathname === '/500'){
return <Page500 />
and this
Option 2
<Route path={'/500'} component={Page500} />
As for me, while the first option displays everything properly for me,
the 2nd one i.e. the router one, shows the component in only half the page.
Now, why is that happening?
Option 1 result -->
Option 2 result -->
But the main point--> what is the difference between using location.path name and router
In Option 2 <Route path={'/500'} component={Page500} />
Here you are creating a Route which has a path of /500 and loads a component Page500. This means that when the user navigates to the path specified in the Route, React-Router will render the component where the Route was defined.
In Option 1 ,
if(location.pathname === '/500'){
return <Page500 />
}
the parent component decides when to render the Page500 component, based on the location prop which it receives. This location prop would ultimately be coming from a Route or the withRouter HOC. This is equivalent to
<Route render={(props)=>{
if(props.location.pathname === '/500'){
return <Page500 />;
}else{
return null;
}
}
}
/>
which can also be written as
<Route path={'/500'} component={Page500} />
So to sum it up, you can only do Option 1 if you get the location prop from the parent component, you can define a Route (Option 2) anywhere in the application.
Edit:
If you have all your Routes like
return( <div>
<Route path={'/500'} component={Page500} />
<Route path={'/confirm-email'} component={PageConfirmEmail} />
<Route path={'/lock-screen'} component={PageLockScreen} />
<Route path={'/login'} component={PageLogin} />
<Route path={'/sign-up'} component={PageSignUp} />
<Route path={'/forgot-password'} component={PageForgotPassword} />
<Route path={'/fullscreen'} component={PageFullscreen} />
</div> );
you are running the risk of multiple Routes rendering which might be why you are getting half page render in Option 2. To prevent that from happening and only render the first Route that matches, you should add a Switch
return( <div>
<Switch>
<Route path={'/500'} component={Page500} />
<Route path={'/confirm-email'} component={PageConfirmEmail} />
<Route path={'/lock-screen'} component={PageLockScreen} />
<Route path={'/login'} component={PageLogin} />
<Route path={'/sign-up'} component={PageSignUp} />
<Route path={'/forgot-password'} component={PageForgotPassword} />
<Route path={'/fullscreen'} component={PageFullscreen} />
</Switch>
</div> );
More on Switch can be found at https://reacttraining.com/react-router/web/api/Switch
One of the main features with react router is that you can do stuff such as:
<Route path="/user/:id" component={User} />
and id will be passed into User component.
Ex. /user/bob and /user/jill will both render a User component, but in your componentDidMount you can now fetch the correct user information from your API.
With location.pathname that task becomes more convoluted as #palsrealm mentioned. But first of all, the location prop must be available for this method to work.
There are other features that you would be losing out, but that is the main one I can think of so far. You can check out the Route api documentation here.
EDIT: As for why it is rendering differently, I really can't answer without more context. For example, is the Route wrapped in a Switch component like so:
<Switch>
// Other routes
<Route exact path="/500" component={Page500} />
</Switch>