Pass something to render function - reactjs

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')}/>

Related

React route: how to obtain the current route key from the component

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

React Router Endpoint with Options

I am trying to define a react route that can contain multiple different options.
I am trying to avoid defining a route for each, like below:
<Route path='/option1' component={Testing}/>
<Route path='/option2' component={Testing}/>
<Route path='/option3' component={Testing}/>
In Express, I am able to do this using app.get('/:name(option1|option2|option3)?', (req, res) => {} and then access this data via req.params.name
Also, is there a way that i can pass the path parameter (i.e option1), into my component via props? How would i do this?
You could store an array of paths and map them to the same Component
['/path','/foo','bar'].map(path => <Route key={path} path={path} component={Foo} />)
Is there a way that i can pass the path parameter (i.e option1), into my component via props?
Yes, just use render instead of component
<Route path='/' render={() => <MyComp myProp='foo'/>}
For url parameters use it like this
<Route path='/path/:param' component={Foo} />
And inside Foo.js
console.log(props.match.params.param)
You could also use regexp
<Route exact path="/path/:foo([0-9a-fA-f]{40})" component={Foo} />
paramenters are set with /myroute:myparam and you can retrieve it in target component with this.props.match.params.myparam

React Router v4 Route difference

I am creating routing for my react app, could someone explain me difference between these two approaches.
From user point of view they work the same, what is the difference in performance, best practice?
First one is multiple Routes rendering different component for the same path:
<Route path='/:shop/booking' component={Services}/>
<Route path='/:shop/booking' component={Calendar}/>
Second is single path rendering components as props.children(?) :
<Route path='/:shop/booking'>
<Aux>
<Services/>
<Calendar/>
</Aux>
</Route>
<Route path='/'>
<Component>
</Route>
Is equivalent to :
<Route path='/' children={Component}/>
According to this : https://reacttraining.com/react-router/core/api/Route/children-func :
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 children render prop receives all the same route
props as the component and render methods, except when a route fails
to match the URL, then match is null. This allows you to dynamically
adjust your UI based on whether or not the route matches.
So by giving children prop instead of component to your route, you force it to render even if the current URL does not match. And I might be mistaking but it seems that adding a component prop to a route override its children prop.
Thus you cannot expect the same behavior for this two pieces of code :
<Route path='/:shop/booking' component={Services}/>
<Route path='/:shop/booking' component={Calendar}/>
Shows the two components for the specified path.
<Route path='/:shop/booking'>
<Aux>
<Services/>
<Calendar/>
</Aux>
</Route>
Shows the two components wrapped in another, for any path.
Finally, I would say that the best practice in React is to wrap your two components into one, and add it to the component prop of a route instead of creating two routes with the exact same path.
If you cannot wrap your two components because one has to be displayed on several routes, you can use something like the following :
<BrowserRouter>
<div>
<Header />
<Switch>
<Route path='/' component={Home}/>
<Route path='/foo' component={Foo}/>
<Route path='/foo2' component={Foo2}/>
</Switch>
<Footer />
</div>
</BrowserRouter>

How to pass props to react-router 4 components?

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 } />
) />

How to Pass Data Through My React-Router with ReactJS?

I have the following JSON object...
{ name: "Jessie" }
And I want to be able to pass it through my Router so that it can be displayed on my pages. For example, this is my root page...
StaticPage.jsx
export default class StaticPage extends React.Component {
render() {
return (
<div>
<Router history={hashHistory}>
<Route path='/' component={Search} />
<Route path='/favorites' component={Favorites} />
</Router>
</div>
);
}
}
So passing this data to Search, I would imagine might look something like this...
<Route path='/' component={Search} name = {this.props.name}/>
However, nothing gets rendered when I do that. I have researched this quite a bit and understand, from what I've read, that you cannot pass objects through the Router. It's very odd bc Router looks like a traditional React component but does not function as such. None of the explanations of a work around seem clear to me. Could anyone provide me with an example using this code? I am using react-router 3.0. There didn't seem to be any magical solution with 4.0 so I figured I'd ask before upgrading. Thanks!
It's because the component prop of <Route> only renders the component with route props, not your supplied props.
You can use the render or component prop on a <Route> in React Router v4 to pass a function which returns a <Search> element that explicitly passes the name:
<Route path="/" render={() => <Search name={this.props.name} />} />
Or with component:
<Route path="/" component={() => <Search name={this.props.name} />} />
But you should prefer render or else you'll have lots of remounting. If you still plan to use route props, you can also do:
render={routeProps => <Search name={this.props.name} {...routeProps} />}
A whole different approach, one more elegant in my opinion is to use route params and pass the name directly through the URL:
<Route path="/:name" component={Search} />
When you navigate to /Bob, you can access this.props.match.params.name which'll give you "Bob".
It is not a good practice to pass the object data via the routes directly. It is recommended to pass a param such as name or id in this way:
<Route path='/favorites/:name' component={Favorites} />
And retrieve it from your request in the destination.
This is a duplicate issue: Pass object through Link in react router

Resources