How to pass props to react-router 4 components? - reactjs

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

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 don't pass value to match.props

So, I started learning React with Redux and react-router. Big mess for a .net
I want to use the match object to find the props in a given url, so I can do this:
function NumberHeader ({match}){
var number = match.props.nr;
..... Logic down here ...
}
I defined a route like this:
<Route path={`/number/:nr`} component={() => <NumberHeader match={this.props.match} />} />
The NumberHeader component is rendering at right url, but I can't get any props.
All this logic is happening not in the App root, it's happening in this rendered componen:
<Route path={routes.NUMERO} component={() => <DrawsPage />} />
What are the key factors that I need to folow, so this will work? I'm using the latest react-router v4. Thanks.
Pass the props from the component declaration:
component={props => <NumberHeader {...props} />}
Alternatively, just do
component={NumberHeader}

Pass something to render function

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

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

Pass props to handler component (that is defined in a variable)

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

Resources