New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Props to handlers on Route #615
Comments
But React Router doesn't do the rendering anymore. So it can't even pass these If all your handlers need same props (e.g. some context), you can do it yourself: router.run(function (Handler, state) {
React.render(<Handler {...state} myProp={something} />;
}); Similarly, you can pass them down to What is your scenario? |
My scenario is that various sub-routes go to the same component, but with different props. Props can be passed to menuComp with React.render(React.createElement(menuComp, props)) And menuComp can pass these props down to ListComp, however, in this scenario various ListComps need different props. I have currently solved this by placing some logic inside ListComp where it checks what list it is, and then sets the various props. However, it would have been more natural to have done that outside. |
Can we make any custom props on |
What I mean is <Route handler={App}>
<Route handler={SomePage} somethingElse='yo'>
... and then router.run(function (Handler, state) {
React.render(<Handler {...state} />;
});
// App
var mountDepth = 0;
return <RouteHandler {...this.props.routes[mountDepth].props} />; This doesn't look very nice because you need to know own mount depth though. (Why doesn't router give you that btw? It should be easy to calculate if each |
👍 I don't really like the factory function approach for handlers either. Instead of using mountDepth, I imagine you could also do some preprocessing in Router.run: router.run(function (Handler, state) {
// build nested route props object
var routeProps = {};
var curRouteProps = routeProps;
state.routes.forEach(function(route){
curRouteProps._childRoute = route.props;
curRouteProps = curRouteProps._childRoute;
});
React.render(<Handler routeProps={routeProps._childRoute} />;
});
// App
return <RouteHandler routeProps={routeProps._childRoute} />; In a similar way, this could also be useful for determining the page title, meta data, flux actions to fire, etc. |
The reason I don't like putting the props on the descriptor (or element, whatever) is because every other place you do that in normal React (i.e. inside your Here, the value of these props never will change, so people get confused and start putting their This is actually one of the strongest arguments for not using descriptors to describe your route hierarchy, IMO. Because props are confusing. |
@gaearon There's a |
Ah, I see your point now. Indeed, to avoid confusion, it might be better to just close over the arguments when needed. Didn't realize |
I just ran into this and wanted to chime in. The close over technique is adding an additional abstraction that really shouldn't be needed. We already have props which are used to pass data into instances of React components. Now we're saying that we need to be able to create custom React components (classes) to pass data in. This seems wholly unnecessary and breaks from reusable conventions. As an example, say I have a reusable React component library. There is no way for me to use those components in the router and configure them with static data because there is no way to create the factory function necessary for the close over technique. In other words, a React component must know that it's going to be used in the router beforehand if we want to be able to pass static data to it. Additionally, I could work around some of the issues if in my render() I could somehow figure out what route is actually being executed. For example, I could call I can somewhat see how people could get confused by the old behavior. However, it was incredibly convenient and the workaround really just doesn't work. Any chance you could reconsider this decision or add in similar functionality through another mechanism? |
Not quite sure what you mean. var SomeComponent = require('library/someComponent');
var MyHandler = React.createClass({
render() {
return <SomeComponent someProp={1} someOtherProp={2} />;
}
});
// ...
<Route handler={MyHandler} ... Why can't you do that? |
@gaearon Yea you're right. After posting I wound up making a factory function that does roughly that.
|
I also figured I should look at the docs since I haven't in awhile. This is solved with the |
@mjackson How do you feel about exposing the machinery to make a Route subclass? (It looks like you've got a handful of functions duplicated in each Route subclass (like That would enable people who want to add static data to the descriptor to do so (by creating a subclass that whitelists the props they need) without having a wildcard free-for-all that confuses new users. Something like: var CustomRoute = ReactRouter._createCustomRouteDescriptor(
{
"myProp": React.propTypes.string
}
);
ReactRouter.run(
<Route>
<CustomRoute
path = "login/"
name = "login"
handler = { require("./components/Login.jsx") }
myProp = "testing"
/>
<Route
path = "welcome/"
name = "welcome"
handler = { require("./components/Welcome.jsx") }
/>
</Route>,
ReactRouter.HistoryLocation,
(Handler, routerState) => {
console.log(
routerState.routes.map(
route => route.myProp
)
);
// "testing"
}
); |
I just wanted to note here that in the new API (see #1158) routes are just plain objects, so you can put whatever props you want on them. Your transition hooks will get a |
Cool. Thanks @mjackson! |
Right now I'm using Alternatives, is there a way I can get the depth of the current active route ? |
@mjackson ^^ |
Why are you commenting on an ancient, closed issue? Anyway, what do you even mean by "current active route"? By the nature of RR being a nested router, there is not in general a single active route but an ordered set of active routes from parent to child. |
Apologies. I meant the current route. So I need to know if the current route is the root or not. Ideally what getDepth would have given me. Is there a replacement for that ? Or can I assume that this.routes will always have the current route at index 1 ? @taion |
There's a couple of things you can do with that, eg: const rootRoute = this.props.routes[0];
const innerRoute = this.props.routes[this.props.routes.length - 1];
const depth = this.props.routes.length;
const myDepth = this.props.routes.indexOf(this.props.route); |
Hold on... why all this mess instead of (proposing) something like <Route name="app" path="/" handler={Page key="value"} /> Are you guys planning on implementing such a thing, or should handlers always be propsless? |
There are no more handlers, just call |
I've been looking into introducing React Router into a project, and was confused by this issue as well as many others. There was no clear answer to "this is how you get parent props into a child component." I threw this together and hope that someone will provide concrete "don't do that" if necessary.
|
@sb8244 I think this is the best possible solution. There is one problem though, and it is that I'm hoping maybe some of the |
My solutions is as follows to get custom props (like a title in my case) from the current route:
|
@lucidlive Shouldn’t you have |
Yeah but it doesn't give me the current active route. The above is the only way I could figure out how to access custom props of the current active route. |
Why is it not possible to do something simple like this? |
I wonder the same. Why not? I've read the entire thread (and others) and still I don't understand how to pass |
Same here. I'd really like to be able to pass in arbitrary props to child components based on the current route. (Either that, or I'd like a way for router.isActive() to do prefix matching, which it currently doesn't do.) The general problem here is that you have some common view component that is rendered via several different routes, but you want to make some minor route-specific tweaks to that component, without having to write a whole new subclass for every route. |
Because Route doesn't render anything, so it can't include any children. The Router only reads its children as a particular kind of configuration, not as plain React elements for rendering. This kind of thing is fixed in 4.0, where |
Route is able to specify components which are passed to the main component: |
React works by easily passing props to components, so a routing system that does not allow it makes no much sense IMHO. |
Yep, that's why 4.0 was built. Go check it out. It's exactly what you're describing.
Because those are React components, not elements. An element is an instance of a React component. Meaning, it has props assigned to it at that point. You can't tell the As a workaround, you can just use higher order functions to do this: const DetailsView = ({ color, fontSize }) => ({ params: { id } }) => (
<div style={{ color, fontSize }}>Project {projects[id].title}</div>
)
const route = <Route components={ProjectView({ color: 'red', fontSize: '16px' })} path="projects/:id" /> Same basic idea for a class: Just wrap it in another function that takes args that you can pass down to the return within the same closure. |
Great, I wasn't aware of it. |
Have problem with HOC wrapped component. It is always remount when I change query params for same route. |
There are a lot of request about passing props from Route to Component (ex remix-run#615 (comment)) This provide access to everything we pass from the Route component without broken its kinda of render
I think it should be simple to add props to handlers. It is a very common scenario to initialize the react components with some starting data as props.
This was changed from 0.10-0.11, and think the suggested workaround with a function closing over the handler is not very good.
What about that Router.Route takes a parameter "props" object that is passed to the handler?
The text was updated successfully, but these errors were encountered: