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这样做最简单,最正确的方法是什么?
#1 楼
UPDATE自新版本发布以来,可以直接通过
Route
组件传递道具,而无需使用包装器。例如,使用render
道具。组件:
class Greeting extends React.Component {
render() {
const {text, match: {params}} = this.props;
const {name} = params;
return (
<React.Fragment>
<h1>Greeting page</h1>
<p>
{text} {name}
</p>
</React.Fragment>
);
}
}
用法:
<Route path="/greeting/:name" render={(props) => <Greeting text="Hello, " {...props} />} />
Codesandbox示例
旧版本
我的首选方法是包装
Comments
组件,并将包装器作为路由处理程序传递。这是您应用了更改的示例:
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);
});
评论
我遇到了同样的问题,但是这种解决方案不是很快变得冗长吗?
– captDaylight
2015年5月5日23:17
同意captDaylight,它变得冗长。宁愿有更好的方法来解决这个问题!
–马提亚斯·霍尔斯特罗姆(MattiasHallström)
15年3月11日在8:31
@mattiashallstrom IMO,1.0中更好的方法是简单地将属性添加到路由。请参阅Thomas E的答案。
–k00k
16年1月8日在17:20
您还可以在其中添加无状态组件语法(仅lambda),它非常短
–中国
16年6月17日19:55
我永远不会同意仅通过传递“首选方式”的属性来创建其他组件。它是冗长,复杂,容易出错的,并且以各种可以想象的方式都是明显错误的。这可能是React Router允许的唯一方式,但是将其称为“ preferred”是很麻烦的。被谁偏爱?
– SzczepanHołyszewski
16-6-29在15:25
#2 楼
如果您不想编写包装器,我想您可以这样做: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}/>
);
评论
这是正确的答案。在react-router 1.0中,您可以在组件中获取路由普通对象。这是github问题的答案:github.com/rackt/react-router/issues/615#issuecomment-100432086
– ycdesu
15/09/26在3:25
这是我一直在寻找的简单答案。其他技术也可以,但是需要的代码量是其的10倍。适用于v1.0.x。我唯一能看到的缺点是,无论您打算使用带有或不带有路由器容器的相同组件。但是对我来说,我所有的顶级组件都通过路由一对一映射。
–killthrush
16年1月4日14:14
万分感谢!如果有人想知道,则foo属性将在您的组件中以如下形式提供:this.props.route.foo
–k00k
16年8月8日在17:12
可以将此设置为正确答案以避免混淆吗?
– Archibald
16年4月8日在20:49
不!真正的解决方案请参见Rajesh Naroth的答案:)
– Alex
16年8月27日在3:24
#3 楼
复制ciantic在接受的答复中的评论:<Route path="comments" component={() => (<Comments myProp="value" />)}/>
我认为这是最优雅的解决方案。有用。帮助了我。
评论
这基本上与上面的包装器答案相同,但是少了很多麻烦。不过,那句语法很烂。尝试抛出_ref
– EdH
16-10-3在17:34
这就像一个匿名包装,因此所有注入的道具(例如位置)都将丢失。必须手动传递诸如component = {(props)=>(
– yuji
16-10-17在11:01
@JacobThomason我们不会重新渲染反应路由器配置,因此不太可能会降低性能。
–塞巴斯蒂安·洛伯(Sebastien Lorber)
16年7月7日在14:21
从React-Router 4开始,如果您提供一个内联函数,您将获得许多不希望的重新安装。对于内联渲染,请使用渲染道具。链接到文档
–丹尼尔·雷纳(Daniel Reina)
17年4月8日在19:26
@yuji为了避免过于混乱,可以执行以下操作:component = {(props)=>(
–apelsinapa
17年8月16日在12:26
#4 楼
这是Rajesh提供的解决方案,没有yuji的不便之处,并且已针对React Router 4进行了更新。代码如下:
<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
请注意,我使用的是
render
而不是component
。原因是避免不必要的重新安装。我还将props
传递给该方法,并且在Comment组件上使用与对象散布运算符相同的道具(ES7提案)。评论
真的也可以解决不必要的安装问题! +1
–GLindqvist
17年11月26日在21:51
#5 楼
只是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})}/>
我尚未测试此解决方案,因此任何反馈都很重要。
请务必注意,使用此方法,通过路由器发送的所有道具(例如params)都将被覆盖/删除。
评论
鲍勃,您熟悉闭包吗? stackoverflow.com/questions/111102/…
–西格马斯
2015年6月5日15:50
而且,如果您还需要路由器的查询和参数,那么类似的方法将起作用:return React.createElement(Component,_.assign({},this.props,props))); (此方法使用_.assign组成组合的对象...当然可以使用其他方法)。
–马尔科姆·德威尔(Malcolm Dwyer)
2015年9月1日在21:33
您可能还想让孩子通过。| var wrapComponent = function(Component,props){return React.createClass({render:function(){return React.createElement(Component,props,this.props.children);}}); };
–朱利奥·罗德里格斯(Julio Rodrigues)
2015年9月13日在1:13
对于不熟悉它们的人来说,这是一个高阶组件。facebook.github.io/ react / docs / higher-order-components.html
–icc97
17年5月27日在19:13
N.B.现在这是旧版本的React Router。当前v4具有Route的render,component和child方法。请注意,正如@dgrcode答案指出的那样,您应该使用render而不是component
–icc97
17年5月27日在20:39
#6 楼
您可以通过将道具传递到<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)
所有子处理程序都将收到相同的道具集-这可能有用吗?情况。
评论
看到React.cloneElement传递了多个元素确实让人感到困惑,但是函数签名似乎只包含一个react元素。我认为此片段可以更容易理解。
–手册
15-10-10在19:38
显然,这是针对文档的最佳答案,但我也同意手册中的建议,即可以更好地显示用法。该问题的特定代码如下所示:React.cloneElement(this.props.children,{myprop:“ value”})或React.cloneElement(this.props.children,{myprop:this.props.myprop})等。
–华尼托甘
16-2-26在22:24
这个答案胜出。 Router会为您执行的操作中发生的事情也更加清楚了。当有人在阅读代码时,如果我知道Comment包含在Index中,我将查看Index以查看将什么道具发送到Comments。如果我碰巧知道Comments是一个路由器处理程序,那么我将查看路由器配置,并找出Index父代注释,然后继续查看。
–mjohnsonengr
16 Mar 28 '16 at 20:53
#7 楼
使用ES6,您可以使组件包装器内联:<Route path="/" component={() => <App myProp={someValue}/>} >
如果需要传递子级:
<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >
评论
很好,但是如果有的话它不会通过孩子。
– zpr
16年8月14日,0:56
@zpr我为props.children添加了一个示例
–尼克
16年8月14日在23:19
正如@dgrcode答案指出的那样,您应该使用render而不是component
–icc97
17年5月27日在20:41
#8 楼
React-router v4 alpha现在,有一种新方法可以做到这一点,尽管与以前的方法非常相似。
br /> PS该功能仅在Alpha版本中有效,并且在v4 Alpha版本后已删除。在最新的v4版本中,它再次是,带有路径和确切的道具。 >
#9 楼
这是我想出的最干净的解决方案(React Router v4):<Route
path="/"
component={props => <MyComponent {...props} foo="lol" />}
/>
MyComponent
仍然具有props.match
和props.location
,并且具有props.foo === "lol"
。#10 楼
用无状态功能组件包装它:<Router>
<Route
path='/'
component={({children}) =>
<MyComponent myProp={'myVal'}>{children}</MyComponent/>
}/>
</Router>
#11 楼
您还可以使用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);
});
评论
它作为ReactRouter.RouteHandlerMixin在全球Bower构建上公开公开,所以我不这么认为。
– jul
15年1月28日在16:37
这也允许使用TransitionGroup和CSSTransitionGroup对过渡进行动画处理,而我使用wrapper方法无法工作。
– jul
15年1月28日在16:41
奇怪的是,官方文档中没有提到这一点。
–科斯梅蒂卡
15年1月28日在18:34
React文档不再推荐使用Mixins:facebook.github.io/react/blog/2016/07/13/…
–icc97
17年5月27日在19:16
#12 楼
您可以通过<RouterHandler/>
传递道具,如下所示:因此,Comments
可能最终会收到实际上用于其他组件的道具,具体取决于您的路线配置。由于props
是不可变的,所以这并不是什么大问题,但是如果两个不同的组件期望一个名为foo
的prop,但是具有不同的值,则可能会出现问题。评论
这三个句点/点在此代码中的作用或含义:{... props}
–巨麋
2015年4月4日2:00
我想Flux可以避免将父App的状态发送到路由的需要。我使上面的代码正常工作,但是它不是很明确,因此隐藏的代码很丑陋,不易跟踪和跟踪正在发生的事情。
–巨麋
2015年4月4日在2:09
传播操作员说明。这不是很明确,但这并不是最坏的事情,因为您传递的是不可变的道具。
– Meistro
2015年4月4日在4:26
这是有关散布运算符的ReactJS文档:facebook.github.io/react/docs/jsx-spread.html以及facebook.github.io/react/docs/transferring-props.html
–巨麋
2015年4月7日在2:15
这对我有用,但是正确的语法是{... this.props}
–赢
2015年7月9日在14:06
#13 楼
在1.0和2.0中,可以使用createElement
的Router
属性来指定如何精确地创建目标元素。文档来源function createWithDefaultProps(Component, props) {
return <Component {...props} myprop="value" />;
}
// and then
<Router createElement={createWithDefaultProps}>
...
</Router>
#14 楼
React Router v 4解决方案今天早些时候我偶然发现了这个问题,这是我使用的模式。希望这对正在寻求最新解决方案的人有用。
我不确定这是否是最佳解决方案,但这是我目前的做法。通常,我有一个Core目录,用于存放常用组件及其相关配置(装载程序,模态等),并包含一个类似这样的文件:
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()从组件生命周期方法愉快地重定向,检查位置等。
希望这会有所帮助!
#15 楼
您还可以结合使用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
}
]
}
评论
我不确定这是如何工作的-但看起来不对。您正在函数中使用this.props,我敢肯定这是行不通的。如果您使用纯函数而不是扩展React.Component,则必须传递prop作为参数,请参阅关于Components和Props的React文档
–icc97
17年5月27日在19:24
#16 楼
对于React Router 2.x.const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;
以及在您的路线中...
<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>
确保第三个参数是一个类似
{ checked: false }
的对象。#17 楼
我已经在这里回答了。有几种方法可以将props传递给路由组件。
使用react-router v5,我们可以通过包装组件来创建路由,以便我们轻松实现将道具传递到所需的组件。
<Route path="/">
<Home name="Sai" />
</Route>
同样,您可以在v5中使用子道具。
<Route path="/" children={ <Home name="Sai" />} />
如果您使用react-router v4,则可以使用渲染道具传递它。
<Route path="/" render={() => <Home name="Sai" />} />
(最初发布在https://reactgo.com/react-router-pass-props/)
#18 楼
React Router的问题在于它渲染了您的组件,因此阻止了您传递道具。另一方面,导航路由器使您可以渲染自己的组件。这意味着您无需跳过任何障碍即可传递道具,如以下代码和随附的JsFiddle所示。#19 楼
根据Rajesh Naroth答案使用带或不带路由器的组件。 >#20 楼
使用如下所示的解决方案,该解决方案可在v3.2.5中使用。 lang-js prettyprint-override“><Route
path="/foo"
component={() => (
<Content
lang="foo"
meta={{
description: lang_foo.description
}}
/>
)}
/>
#21 楼
React Router v5.1(反应> = 16.8)的执行方式:<Route path="/comments">
<Comments myprop="value" />
</Route>
现在,如果要访问组件内部的Route Props,则可以参考此解决方案。如果是功能组件,则该帖子中未提及另一个钩子
useParams()
。评论
⚠注意:您将失去对
–spShuvo先生
20 Dec 30'0:37
@ Mr.spShuvo你错了。我已经更新了答案。检查出。对于类组件,只需要withRouter;对于功能组件,只需要钩子即可。
–brc-dd
20/12/30在11:17
好吧,可能是我部分错了。但是对于类组件,您不能使用钩子。感谢您的更新和更多参考链接。
–spShuvo先生
20 Dec 30 '13:27
#22 楼
对于React-Router 2.5.2,解决方案非常简单: //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'})}
)
}
...
#23 楼
使用自定义路由组件,这可以在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
#24 楼
这可能是将react-router-dom与cookie处理程序一起使用的最佳方法在index.js中
import React, { Component } from 'react'
import {Switch,Route,Redirect} from "react-router-dom"
import {RouteWithLayout} from "./cookieCheck"
import Login from "../app/pages/login"
import DummyLayout from "../app/layouts/dummy"
import DummyPage from "../app/pages/dummy"
export default ({props})=>{
return(
<Switch>
<Route path="/login" component={Login} />
<RouteWithLayout path="/dummy" layout={DummyLayout} component={DummyPage}
{...props}/>
<Redirect from="/*" to="/login" />
</Switch>
)
}
并使用cookieCheck
import React , {createElement} from 'react'
import {Route,Redirect} from "react-router-dom"
import {COOKIE,getCookie} from "../services/"
export const RouteWithLayout = ({layout,component,...rest})=>{
if(getCookie(COOKIE)==null)return <Redirect to="/login"/>
return (
<Route {...rest} render={(props) =>
createElement(layout, {...props, ...rest}, createElement(component,
{...props, ...rest}))
}
/>
)
}
#25 楼
class App extends Component {
constructor(props){
super(props);
this.state = {
data:null
}
}
componentDidMount(){
database.ref().on('value', (snapshot) =>{
this.setState({
data : snapshot.val()
})
});
}
render(){
// const { data } = this.state
return (
<BrowserRouter>
<Switch>
<Route exact path = "/" component = { LandingPage } />
<Route
path='/signup'
render = { () => <Signup data = {this.state.data} />} />
</Switch>
</BrowserRouter>
);
}
};
export default App;
评论
这里的问题,在类似的情况下,尤其是用某些lang编写的框架或库,显然缺乏组合手段(MoC)。在React中,原语似乎还不错,它们在React元素中使用原语定义组件,而组件MoC在React中似乎也不错。但是结合的手段是不完整的。一个组件必须能够将道具传递给一个组件,同时又将一个组件与另一个组件组合在一起,这无关紧要,方法是将一个组件作为另一个组件的子组件放置在另一个组件中,或者将一个组件作为道具传递给另一个组件。使用某些语法,例如