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
Related
So basically title is my question. Is it possible to achieve something like this with only url paramater change:
<Route path={'/users/:id'} component={()=> UsersPage}/>
<Route path={'/users/:filterOption'} component={()=> UsersList}/>
react-router-dom#5
Yes, absolutely you can. The Router component inclusively matches and renders routes (as opposed to the Switch component that exclusively matches them). This means the Router will render all routes and redirects that are matched by the path prop.
Given path `"/users/someValue":
<Router>
<Route path={'/users/:id'} component={()=> UsersPage}/>
<Route path={'/users/:filterOption'} component={()=> UsersList}/>
</Router>
Both components can be matched and rendered.
Note about Route component prop!
Route render methods
When you use component (instead of render or children) 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.
This means you should not use the component prop if you are providing a function. Instead do one of the following
<Router>
<Route path={'/users/:id'} component={UsersPage}/>
<Route path={'/users/:filterOption'} component={UsersList}/>
</Router>
or
<Router>
<Route path={'/users/:id'} render={()=> <UsersPage />}/>
<Route path={'/users/:filterOption'} render={()=> <UsersList />}/>
</Router>
or
<Router>
<Route path={'/users/:id'}>
<UsersPage />
</Route>
<Route path={'/users/:filterOption'}>
<UsersList />
</Route>
</Router>
react-router-dom#6
react-router-dom#6 now always exactly matches and uses a path ranking/scoring system and '/users/:id' and '/users/:filterOption' have the same specificity and will have the same score. There's nothing to disambiguate between them. Instead you'll rendering a single route and need to use the useParams hook to read the route param, either in a wrapper component or directly in the routed components.
Example with wrapper component.
const UserWrapper = () => {
const { id } = useParams();
return (
<>
<UsersPage id={id} />
<UsersList filterOption={id} />
</>
);
};
...
<Router>
<Routes>
<Route path={'/users/:id'} element={<UserWrapper />} />
...
</Routes>
</Router>
Yes, we can do that in react-router, Just check this article, it has best example for Dynamic URL Parameters.
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
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')}/>
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