I have something like this:
<Route path="/route/:param" component={DealContainer} />
Then while the component is mounted I am doing a client side redirect:
componentWillMount() {
if (this.props.match.params.param != 'desired_one') {
this.props.history.push('/route/desired_one');
Despite the fact that the url changes the component is not remounted...
Any ideas?
You should resolve this issue by using the Redirect component inside "react-router-dom" package
<Route exact path="/route" component={DealContainer} />
<Route
exact
path="/route/desired"
render={() => <Redirect to="/route/desiredRedirectLocation" />}
/>
<Route path="/route/:param" component={DealContainer} />
This implementation should:
Match the exact base route correctly, without matching any props. Lets say that you want to show a list of items (e.g. /products)
Match the desired item to be redirected (e.g. products/car) and redirect it to the desired location, let's say products/horse
Match any other case that you don't want to redirect /products/:id and correctly take the prop you are after inside the match object.
Explanation
The problem with history.push, is that React will figure out you are using the same component, and will only update the differences, without actually re-mounting the component, which is already mounted.
My example with redirect on the other hand, will intercept the route you want to redirect without mounting the component first, so component will be mounted after the redirect happened, correctly executing the action that you need.
Related
I'm trying to create an independent Route (not sure if that's the correct term) at BulletinBoard.js where I can use Link to go to Create Bulletin component.
I'm also trying to create another independent Route at BulletinList.js where I can navigate to Edit Bulletin with their respective IDs.
Before this, I tried using useRouteMatch with path and url, but apparently that wasn't the correct way to do it, now I'm told to use useLocation, it does adds the /createbulletin and /editbulletin/id paths behind the current URL, but it doesn't navigate to the component itself.
I've been cracking my head over this for the past 2 days and I still haven't figured out the correct way to do this.
Here is the codesandbox that I've created for reference.
The reason your code didnt navigate to a different component after the url changed is because you didnt use the exact attribute when declaring the route. So its matching /bulletinboard/anything and then it always renders de BulletinBoard component.
You could define all routes at the App.js file like
<Switch>
<Route path="/" component={Home} exact />
<Route path="/bulletinboard" component={BulletinBoard} exact />
<Route path="/bulletinboard/edit/:id" component={EditBulletinBoard} exact />
<Route path="/infohub" component={InfoHub} exact />
<Route component={NotFound} />
</Switch>
Also, check out the useHistory hook
So at the BulletinBoard.js when the user clicks the link
onClick={() => history.push(`/bulletinboard/edit/${id}`)}
Note that the edit route renders a different component that your codesandbox didn't have yet
I have a Profile component that checks to see if the user passed in url params. If not, the Profile component will render using the current logged in user. If they did, it will pull that value and use that userid for the Profile form.
Everything renders. And the proper profiles eventually appear, however if the user passes in different userid to view, the form will first render their own Profile...THEN render the passed in user.
I'm fairly confident that it's an issue of the props not being set at the time the first render occurs. My question is how can I prevent this?
I'm using react router 4.0. I setup a parent child component trying to do a conditional render...nothing seems to help.
My parent render function looks like this:
{this.props.match.params.userId && (
<ProfileForm
key={this.props.match.params.userId}
profileId={this.props.match.params.userId}
/>
)}
{!this.props.match.params.userId && <ProfileForm />}
My Route statement is this:
<Route exact={true} path={routes.PROFILE} component={Profile} />
<Route path={`${routes.PROFILE}/:userId`} component={Profile} />
Is there a way to prevent it from loading the "non-propped" version first or do I have to create a new component for "others" and have the route go there first?
I just took over a React project from one of my colleague but I cannot understand the logic in the code below.
content = <Switch>
<Route path="/login" exact component={LoginPage} />
<Route render={() => { return <Redirect to="/login" />; }} />
</Switch>
I know how to use Route with Component, with Render, but Render with Redirect, first time I saw it.
Thanks
This appears to be just another way of just saying:
<Redirect path='*' to='/login' />
Since it is inside a <Switch>, and after any <Route>, it will always match (if nothing above it got matched) and get rendered.
When the Redirect component gets rendered, it does its job of redirecting to the page specified in the to prop.
I found that out by doing some reading of the source code. If you're interested, there's a bit of indirection, but basically the Redirect component renders a Lifecycle component which will call method with the location provided as soon as it's mounted.
method is set like this:
const method = push ? history.push : history.replace;
And that's done like that because apparently the <Redirect> component can take push as a boolean prop, to set the behaviour of how the redirect is actually achieved.
Redirect component source https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Redirect.js
Lifecycle component source: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Lifecycle.js
I have routes defined like following:
<Route path="auth">
<Route path="confirm-code" component={this.getIndexRoute()} email="xyz#gmail.com" code="1234" />
</Route>
getIndexRoute() gives me a component to navigate to. When I hit http://localhost:3000/de/auth/confirm-code/ it works.
However, I want to modify this path to be like http://localhost:3000/de/auth/confirm-code/email=someEmail&code=someCode
I would then want to pass those received email and code as props to my component so that I can process them there. right now I am hard-coding email="xyz#gmail.com" and code=1234. I would like to extract them from the url.
How to do it?
All query params (email, code) are automatically passed to the component via props.location - or depending on which router version you are using you can use withRouter
react-router getting this.props.location in child components
I have a React MaterialUI AppBarcomponent with property title , that I am changing based on the value returned by window.location.pathname. So as the page/url changes, the title will change with it. Looks something like below:
<AppBar
title={this.renderTitle()}
/>
renderTitle() {
if (window.location.pathname === '/home'
return 'home';
} else if (window.location.pathname === '/login'
return 'login';
}
The issue I am running into is that renderTitle() does not get executed if a different component (so not the AppBar) causes the page/url change.
E.g. another separate React component on the page triggers the page to change, which I'd hoped with trigger renderTitle(), but it doesn't... thus the title property never updates. So if I am navigating from /home to /login, the following will happen:
pathname is /home
user presses a button which runs a function, submit(), which is used to change the page w/ react-router
renderTitle() is run at this point, but window.location.pathname is still returning the previous page
submit() changes the page to /login
window.location.pathname is now correctly set to /login, but it is too late as renderTitle() has already been run
any help is appreciated, thanks
The best way is to use react-document-title library.
From documentation:
react-document-title provides a declarative way to specify document.title in a single-page app.
This component can be used on server side as well.
If your component that renders AppBar is an actual route you can just read the pathname from the props that react router injects.
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
<Route path="messages/:id" component={Message} />
</Route>
</Route>
</Router>
For example in App, About, Inbox and Message you have access to the router props. And you can also pass the props to their children.
render() {
return (
<AppBar
title={this.renderTitle(this.props.location.pathname)}
/>
);
}
And in your function just use the parameter to return the correct result. Now because you are using props your component will update automatically when they change.