In my parent App.js file I have :
<Route path="/login" component={Login} onFormSubmit={this.onLoginSubmit} />
But in Login.js when I do :
this.props.onFormSubmit(this.state.email, this.state.password);
I get : TypeError: this.props.onFormSubmit is not a function
EDIT : I see that this is a workaround :
<Route path="/login" render={(props) => (<Login onFormSubmit={this.onLoginSubmit} {...props} />)} />
Or this the only / right way to get this working like this ?
You should use render props like this.
<Route
path='/login'
render={(props) => (
<Login onFormSubmit={this.onLoginSubmit} />
)}
/>
I am assuming that you are using react-router-dom here. In that case, the Route component injects only three properties to the component property, Login.
You may refer to https://reactrouter.com/web/api/Route/route-props, but basically only the following values will be exposed (i.e. injected) by Route to the Login component:
match
A match object contains information about how a matched the URL
location
Locations represent where the app is now, where you want it to go, or even where it was
history
The term “history” and "history object" in this documentation refers to the history package, which is one of only 2 major dependencies of React Router (besides React itself), and which provides several different implementations for managing session history in JavaScript in various environments
Hence, passing an arbitrary property value like onFormSubmit will not work since Route does not inject it into the child component. That's the reason why you're getting the TypeError. If you really need to expose this.onLoginSubmit, I suggest you use React context, aside from the answer by Nilesh that uses render props.
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 wanted to understand the exact differences between the 2 ways of writing React <Route /> i.e. one with "render" and other with "children" prop;
// With "render"
<Route
path={route.path}
render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes} />
)}
/>
// With "children"
<Route
path={route.path}
exact={route.exact}
children={props => <route.component {...props} routes={route.routes} />}
/>
Also, with the 2nd use case (i.e. with "children"), what difference does it make when exact property is true v/s false ?
From the docs of
React Router's render function
This allows for convenient inline rendering and wrapping without the undesired remounting explained above.Instead of having a new React element created for you using the component prop, you can pass in a function to be called when the location matches
And
React Router's children function
Sometimes you need to render whether the path matches the location or not. In these cases, you can use the function children prop. It works exactly like render except that it gets called whether there is a match or not.
The main difference as per what I understand is that when we pass a component as children prop then that component will get rendered even if the location matches or not.
I have created a sample app in order to simulate the same, here is the app
I have a React route like code below:
<Route path='/settings' component={Settings} />
And inside Settings component, it has 3 nested routes:
<Route path='/settings/general' component={GeneralSetting} />
<Route path='/settings/team' component={TeamSetting} />
<Route path='/settings/email' component={EmailSetting} />
So my question is how can I get the nested pathname at most right position (such as '/general', '/email') only without the parent route ('/settings'). Currently, I'm using string splitter on location pathname (/settings/general) to achieve this. Are there any best practice for this situation?
I appreciate any help. Thanks in advance.
IMO, there are no best practice to get child path in react router. You are using string splitter on location which is fine though.
If you still need to get child path only you can use params in url instead and render component on based of params like below
<Route path='/settings/:type' component={Type} />
In Type (new component to render child) component you can get params like below
this.props.match.params.type
that will give you general , team and email value based on your url.
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
Current routes:
// React render() return example
<Switch>
<Route path="/" exact render={this.renderPage}/>
<Route path="/search" render={this.renderPage}/>
<Route path="/profile" render={this.renderPage}/>
<Route render={this.renderPage}/>
</Switch>
// here's the simplified method that Route-s call if path matches
renderPage(props) {
// JS logic is here
return [
<ItemHeader key="header"/>,
<ItemWrapper key="wrapper">
{/* this is what the question is about: */}
{/* how do I pass this dynamic Component here or even hint about it? */}
<Component someProp={varBasedOnJSLogicAbove}/>
</Wrapper>
];
}
How to pass any data to renderPage method?
I need to pass my component as variable (or any hint really - string etc) to renderPage method because I need to tell it what component I want it to render.
Why do you even need renderPage method?
There's JavaScript logic and I also need to wrap my Component with other components.
1. Why don't you use component prop on Route?
<Route path="/profile" component={Profile}/>
Because I need to wrap the component and inject some data into it, like in renderPage method.
2. Why don't you create a separate React component and do all the renderPage logic and wraping in it? You could pass everything you need as props, etc:
<CustomRoute path="/profile" component={Profile} anyThing="ILikeToPass"/>
Tried it, unfortunately it breaks Switch (I really need it), Route has to be direct child.
3. Why don't you use different method for every route? E.g renderProfile.
20 methods and each has exactly the same code except different Component? No thanks!
4. Why don't you just pass the data as function/method arguments?
<Route path="/profile" render={this.renderPage(Component, 'foo')}/>
// or
<Route path="/profile" render={() => this.renderPage(Component, 'bar')}/>
Doesn't work as needed. First option seems to overwrite the props (I need those) that React Router passes to my method and if you use arrow function - it passes only props, not my args.
5. Why don't you use pathname and figure it out yourself?
Use a single Route without path prop and do all the pathname parsing and logic in my method? That's a big if not the point of using a router and Route-s.. I don't want to rebuild the router.
So, this is an answer:
Why not try:
<Route path="/profile" render={(props) => this.renderPage(props, Component, 'bar')}/>