react-router – 将道具传递给处理程序组件
对于使用React Router的 React.js应用程序,我有以下结构:
var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var Index = React.createClass({ render: function () { return ( <div> <header>Some header</header> <RouteHandler /> </div> ); } }); var routes = ( <Route path="/" handler={Index}> <Route path="comments" handler={Comments}/> <DefaultRoute handler={Dashboard}/> </Route> ); ReactRouter.run(routes, function (Handler) { React.render(<Handler/>, document.body); });
我想将一些属性传递给Comments
组件。
(通常我会这样做<Comments myprop="value" />
)
React Router最简单和正确的方法是什么?
我喜欢的方式是包装Comments
组件,并传递包装作为路由处理程序。
更新此方法是一个临时解决scheme。 现在你可以直接通过Route
组件传递道具,而不需要使用Wrapper。
这是您应用更改的示例:
var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var CommentsWrapper = React.createClass({ render: function () { return ( <Comments myprop="myvalue" /> ); } }); var Index = React.createClass({ render: function () { return ( <div> <header>Some header</header> <RouteHandler /> </div> ); } }); var routes = ( <Route path="/" handler={Index}> <Route path="comments" handler={CommentsWrapper}/> <DefaultRoute handler={Dashboard}/> </Route> ); ReactRouter.run(routes, function (Handler) { React.render(<Handler/>, document.body); });
如果你不想写包装,我想你可以这样做:
class Index extends React.Component { constructor(props) { super(props); } render() { return ( <h1> Index - {this.props.route.foo} </h1> ); } } var routes = ( <Route path="/" foo="bar" component={Index}/> );
在接受的回复中从ciantic的评论中复制:
<Route path="comments" component={() => (<Comments myProp="value" />)}/>
我认为这是最优雅的解决scheme。 有用。 帮助过我。
只是ColCh的回答。 抽象组件的包装是很容易的:
var React = require('react'); var wrapComponent = function(Component, props) { return React.createClass({ render: function() { return React.createElement(Component, props); } }); }; <Route path="comments" handler={wrapComponent(Comments, {myprop: value})}/>
我还没有testing过这个解决scheme,所以任何反馈都很重要。
请注意,使用此方法,通过路由器发送的任何道具(例如params)都会被覆盖/删除。
你可以通过传递道具到<RouteHandler>
(在v0.13.x中)或v1.0中的Route组件本身来传递道具。
// v0.13.x <RouteHandler/> <RouteHandler someExtraProp={something}/> // v1.0 {this.props.children} {React.cloneElement(this.props.children, {someExtraProp: something })}
(来自https://github.com/rackt/react-router/releases/tag/v1.0.0的升级指南);
所有的童工都会收到相同的道具 – 这可能是有用的或不是根据情况。
这是Rajesh的解决scheme ,没有不方便的yuji评论 ,并更新了反应路由器4。
代码将是这样的:
<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
请注意,我使用render
而不是component
。 原因是为了避免不必要的重新安装 。 我也把props
传给了这个方法,而且我在评论组件上使用了与对象扩展运算符(ES7提议)相同的道具。
使用ES6,你可以使组件包装内联:
<Route path="/" component={() => <App myProp={someValue}/>} >
如果你需要通过孩子:
<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >
React-router v4 alpha
现在有一个新的办法,做到这一点,虽然与以前的方法非常相似。
import { Match, Link, Miss } from 'react-router'; import Homepage from './containers/Homepage'; const route = { exactly: true, pattern: '/', title: `${siteTitle} - homepage`, component: Homepage } <Match { ...route } render={(props) => <route.component {...props} />} />
PS这只适用于alpha版本,并在v4 alpha版本后被删除。 在最新的v4中,是再一次的道路和精确的道具。
react-lego一个示例应用程序包含代码,它在react-router-4分支上的routes.js中正好执行此操作
这是我提出的最干净的解决scheme(React Router v4):
<Route path="/" component={props => <MyComponent {...props} foo="lol" />} />
MyComponent
仍然有props.match
和props.location
,并有props.foo === "lol"
。
你可以像这样通过<RouterHandler/>
传递道具:
var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var Index = React.createClass({ render: function () { var props = this.props; // or possibly this.state return ( <div> <header>Some header</header> <RouteHandler {...props} /> </div> ); } });
这个缺点是你不加区分地通过道具。 所以Comments
可能最终会收到根据您的路线configuration真正用于不同组件的道具。 由于props
是不可改变的,这并不是什么大问题,但是如果两个不同的组件需要一个名为foo
的道具,但是具有不同的值,这可能会有问题。
您也可以使用RouteHandler mixin来避免包装器组件,并更轻松地传递父代的状态作为道具:
var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var RouteHandler = require('react-router/modules/mixins/RouteHandler'); var Index = React.createClass({ mixins: [RouteHandler], render: function () { var handler = this.getRouteHandler({ myProp: 'value'}); return ( <div> <header>Some header</header> {handler} </div> ); } }); var routes = ( <Route path="/" handler={Index}> <Route path="comments" handler={Comments}/> <DefaultRoute handler={Dashboard}/> </Route> ); ReactRouter.run(routes, function (Handler) { React.render(<Handler/>, document.body); });
用无状态函数组件包装它:
<Router> <Route path='/' component={({children}) => <MyComponent myProp={'myVal'}>{children}</MyComponent/> }/> </Router>
在1.0和2.0中,你可以使用Router
createElement
来指定如何创build你的目标元素。 文档来源
function createWithDefaultProps(Component, props) { return <Component {...props} myprop="value" />; } // and then <Router createElement={createWithDefaultProps}> ... </Router>
你也可以结合es6和无状态函数来得到更清晰的结果:
import Dashboard from './Dashboard'; import Comments from './Comments'; let dashboardWrapper = () => <Dashboard {...props} />, commentsWrapper = () => <Comments {...props} />, index = () => <div> <header>Some header</header> <RouteHandler /> {this.props.children} </div>; routes = { component: index, path: '/', childRoutes: [ { path: 'comments', component: dashboardWrapper }, { path: 'dashboard', component: commentsWrapper } ] }
对于反应路由器2.x.
const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;
并在你的路线…
<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}> </Route>
确保第三个参数是一个对象,如: { checked: false }
。
React Router v 4解决scheme
我今天早些时候偶然发现了这个问题,这里是我使用的模式。 希望这对任何想要更新的解决scheme的人都有用。
我不确定这是否是最好的解决scheme,但这是我目前的模式。 我通常有一个核心目录,我保留我的常用组件与他们的相关configuration(装载机,模态等),我包括这样一个文件:
import React from 'react' import { Route } from 'react-router-dom' const getLocationAwareComponent = (component) => (props) => ( <Route render={(routeProps) => React.createElement(component, {...routeProps, ...props})}/> ) export default getLocationAwareComponent
然后,在有问题的文件中,我将执行以下操作:
import React from 'react' import someComponent from 'components/SomeComponent' import { getLocationAwareComponent } from 'components/Core/getLocationAwareComponent' const SomeComponent = getLocationAwareComponent(someComponent) // in render method: <SomeComponent someProp={value} />
您会注意到我将组件的默认导出导入为驼峰式,这让我可以在CamelCase中命名新的位置感知组件,以便我可以正常使用它。 除了额外的导入线和分配线之外,组件的行为与预期一样,并且正常接收其所有道具,并添加所有的道具道具。 因此,我可以很高兴地使用this.props.history.push()从组件生命周期方法redirect,检查位置等。
希望这可以帮助!
React路由器的问题是它渲染你的组件,所以阻止你传递道具。 另一方面, 导航路由器可让您渲染自己的组件。 这意味着你不必像下面的代码和JsFiddle表演一样跳过道具传递道具。
var Comments = ({myProp}) => <div>{myProp}</div>; var stateNavigator = new Navigation.StateNavigator([ {key:'comments', route:''} ]); stateNavigator.states.comments.navigated = function(data) { ReactDOM.render( <Comments myProp="value" />, document.getElementById('content') ); } stateNavigator.start();
根据Rajesh Naroth的回答,使用带或不带路由器的组件。
class Index extends React.Component { constructor(props) { super(props); } render() { const foo = (this.props.route) ? this.props.route.foo : this.props.foo; return ( <h1> Index - {foo} </h1> ); } } var routes = ( <Route path="/" foo="bar" component={Index}/> );
或者你可以这样做:
export const Index = ({foo, route}) => { const content = (foo) ? foo : (route) ? route.foo : 'No content found!'; return <h1>{content}</h1> };
对于反应路由器2.5.2,解决scheme非常简单:
//someConponent ... render:function(){ return ( <h1>This is the parent component who pass the prop to this.props.children</h1> {this.props.children && React.cloneElement(this.props.children,{myProp:'value'})} ) } ...
使用一个自定义的路由组件 ,在React Router v3中是可能的。
var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var routes = ( <Route path="/" handler={Index}> <MyRoute myprop="value" path="comments" handler={Comments}/> <DefaultRoute handler={Dashboard}/> </Route> );
至于<MyRoute>
组件的代码,它应该是这样的:
import React from 'react'; import { Route } from 'react-router'; import { createRoutesFromReactChildren } from 'react-router/lib//RouteUtils'; const MyRoute = () => <div><MyRoute> elements are for configuration only and should not be rendered</div>; MyRoute.createRouteFromReactElement = (element, parentRoute) => { const { path, myprop } = element.props; // dynamically add crud route const myRoute = createRoutesFromReactChildren( <Route path={path} />, parentRoute )[0]; // higher-order component to pass myprop as resource to components myRoute.component = ({ children }) => ( <div> {React.Children.map(children, child => React.cloneElement(child, { myprop }))} </div> ); return myRoute; }; export default MyRoute;
有关自定义路由组件方法的更多详细信息,请查看关于此主题的博客文章: http : //marmelab.com/blog/2016/09/20/custom-react-router-component.html