Similar to react-router - pass props to handler component but in my case my component was declared in a variable in my case elem.component and I am trying to build an array of routes passing a showModal function.
This is what I had tried so far
routes.push(
<Route key={elem.to} exact path={elem.to}
component={elem.component} showModal={this.props.showModal}/>)
I was looking at the render methods for the other answers but they have the component defined in the function which I do not have in my case.
Just pass component using function binding
<Route exact path="/" component={() => (<Component prop={val} />) }/>
You have to assign component to a capitalized variable to use it in JSX - please check this React docs for more details about defining element type at runtime. Please try this:
<Route key={elem.to} exact path={elem.to}
render={() => {
const MyComponent = elem.component;
return <MyComponent showModal={someValue} />
}}
/>
Related
Say, I have the following wrapper:
<Switch>
<Route path={`/app/list`} component={ListPage} key="list"/>
<Route path={`/app/view`} component={EditPage} key="view"/>
<Route path={`/app/edit`} component={EditPage} key="edit"/>
<Route path={`/app/new`} component={EditPage} key="new"/>
</Switch>
When I load the corresponding component, say ListPage, I want to be able to get the key of the current route, in this case, it would be "list".
If I check this.props.match, I have only isExact, params, path, url but not the key.
You don't get the key property because you just provide the component that you want to get rendered by the Router to the Route component and this way you cannot specify what props your component will accept except the default ones - match, location, history. You can read more about it here.
You can use the render prop in order to specify how to render the component by providing a render function and this way you can specify the props that your component will accept for example - key. The function will have all the default props provided by the router and you can just spread them as props on your component.
Since key and ref are reserved props in React and they are not passed to the component, I've renamed the key prop to keyName. More info can be found here.
It will look like:
<Switch>
<Route path="/app/list" render={(props) => <ListPage {...props} keyName="list"/>} />
<Route path="/app/view" render={(props) => <EditPage {...props} keyName="list"/>}/>
<Route path="/app/edit" render={(props) => <EditPage {...props} keyName="edit"/>} />
<Route path="/app/new" render={(props) => <EditPage {...props} keyName="new" />}/>
</Switch>
and you will be able to access the key by using props.key inside the component that is rendered.
Of course it would be better to extract the render function into a function called renderWithKey or something in order remove the duplication so the code to be cleaner.
It's reserved property used in react or react-router internally
If you want to get list use different property. ref, key are reserved
I am trying to pass props to my components through the accepted way from various sources like this comment
This is my current code
<Router>
...
<Route path="/:id" exact component={() => <GymMain id={params.id} appointmentTypes={appointmentTypeList} />} />
<Route path={`/:id/:name`} component={(props) => {
const { params } = props.match;
const aType = appointmentTypeList.find(at => at.uri === params.name);
return <AppointmentType id={params.id} appointmentType={aType} />
}} />
...
</Router>
However this causes the components to mount twice, once when you navigate into it and then when you navigate away from it (while navigating away old props are passed). This is happening because I am decorating my original component with an anonymous one as explained in this answer .
My Question is how can I prepare the props for child components based on the route params and then pass it on to the routed component. Thanks!
There is a small difference between using component prop vs render prop to render a functional component.
As per the docs:
When you use component (instead of render or children, below) the
router uses React.createElement to create a new React element from
the given component. That means if you provide an inline function to
the component prop, you would create a new component every render.
This results in the existing component unmounting and the new component mounting instead of just updating the existing component.
When using an inline function for inline rendering, use the render or
the children prop (below).
Hence you see the above behaviour in your case. Change your code to use render prop and it would work fine
<Router>
...
<Route path="/:id" exact render={() => <GymMain id={params.id} appointmentTypes={appointmentTypeList} />} />
<Route path={`/:id/:name`} render={(props) => {
const { params } = props.match;
const aType = appointmentTypeList.find(at => at.uri === params.name);
return <AppointmentType id={params.id} appointmentType={aType} />
}} />
...
</Router>
This is not the best way for doing so.
you can use UNSAFE_componentWillUpdate() lifecylcle method to check incoming props.
UNSAFE_componentWillUpdate(nextProps, nextState){
// check for your condition for updating component
if (this.porps !== nextProps) {
this.forceUpdate()
}
else {
return
}
}
const Home = () => <div>Home</div>
const App = () => {
const someVariable = true;
return (
<Switch>
{/* these are good */}
<Route exact path='/' component={Home} />
<Route
path='/about'
render={(props) => <About {...props} />}
/>
</Switch>
)
}
const About = (props) => {
return (
<div>
About
</div>
)
}
In the code sample , at
<Route
path='/about'
render={(props) => <About {...props} />}
/>
when react encounters the render prop of the Route component which is part of react-router, what does it pass a props?
Given the documentation at https://reactjs.org/docs/render-props.html ,
a render prop is a function prop that a component uses to know what to render,
is the value passed a props buried inside the declaration of Route in react-router
The props are passed to the render prop method by the Route component. You can see this in the React Router source code. The props passed by the Route component have match, location, history, staticContext. If you want to use props from the parent component, where you are defining the render props method then you can omit the props argument.
render={() => <About {...props} />}
Then you would get the props from the component that contains the Route.
The example you have provided doesn't make much sense since that replicates the behaviour that you get by just using the 'component' prop on the Route.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Route.js#L120
We use Route with render props as,
<Route path = "/about" component={About} />
OR,
<Route path = "/about" render= { (props) => <About {...props} } />
The second one is different from the first one in the sense that in the second case, the About component has access to the props coming through the Route.
Say, for instance,
there is a Profile component,
<Route path="/admin/profile"
render={ props => (
<Profile tabs= {"valuePassed"} {...props} />
)}
/>
Now in Profile component, we can access all the props,
this.props.tabs give "valuePasses" in class-based component while props.tabs is used for functional component.
Hope this helps.
You get react router default props while passing props in render method just like if use component instead of using render props which implicitly get all these props match, location, history and staticContext. and you need to provide props as an argument otherwise it render method won't pass props down to the children because it will consider it undefined.
Here is working example for render props in react router:
https://codesandbox.io/s/72k8xz669j
Id like to use my app entry point as a global state store. Passing info down to children as props.
Using react-router 4, how can I send prop data down to the rendered components. In a similar fashion to this:
<Route Path=“/someplace” component={someComponent} extra-prop-data={dataPassedToSomeComponent} />
I’ve seen some janky workarounds for older versions of react-router, that appear to be deprecated.
What is the correct way of doing this in v4?
You can pass in a function to the render prop instead of passing in the component directly to the component prop.
<Route path="/someplace" render={() => <SomeComponent props={} />} />
You can read more here.
And to add to the above answer, if you want the routing properties accessible to the component you need to include those. Now when the router activates "SomeComponent", the component will get all the routing props plus the extra param(s) - in this example "param".
<Route path='/someplace' component={(props) => <SomeComponent param="yo" {...props}/>} />
Technically there is 2 ways to do it.
The first one (not the most efficient) is to pass an inline function to the component prop:
<Route
path=“/someplace”
component={(props) => (
<SomeComponent {...props} extra-prop-data={ dataPassedToSomeComponent } />
) />
The second one is the best solution. To prevent create a new component on every render like on the first exemple, we pass the same inline function but this time to the render prop:
<Route
path=“/someplace”
render={(props) => (
<SomeComponent {...props} extra-prop-data={ dataPassedToSomeComponent } />
) />
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')}/>