我使用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最简单,最正确的方法是什么?
答案 0 :(得分:256)
如果你不想写包装,我想你可以这样做:
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}/>
);
答案 1 :(得分:130)
自新版本发布以来,可以直接通过Route
组件传递道具,而无需使用Wrapper。例如,using render
prop。
<强>组件:强>
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} />} />
我首选的方法是包装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);
});
答案 2 :(得分:111)
在接受的回复中复制ciantic的评论:
<Route path="comments" component={() => (<Comments myProp="value" />)}/>
在我看来,这是最优雅的解决方案。有用。帮帮我。
答案 3 :(得分:52)
这是solution from Rajesh,没有不方便的commented by yuji,并针对React Router 4进行了更新。
代码如下:
<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
请注意,我使用render
代替component
。原因是要避免undesired remounting。我还将props
传递给该方法,并在使用对象扩展运算符(ES7提议)的Comments组件上使用相同的道具。
答案 4 :(得分:43)
只是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)都会被覆盖/删除。
答案 5 :(得分:30)
您可以通过将道具传递到<RouteHandler>
(在v0.13.x中)或路径组件本身在v1.0中传递道具;
// 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的升级指南)
所有儿童处理程序都将获得相同的道具 - 根据具体情况,这可能有用或无用。
答案 6 :(得分:23)
使用ES6,你可以直接制作组件包装器:
<Route path="/" component={() => <App myProp={someValue}/>} >
如果你需要传递孩子:
<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >
答案 7 :(得分:22)
现在有一种新方法可以做到这一点,尽管与之前的方法非常相似。
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} />} />
P.S。这仅适用于alpha版本,并在v4 alpha版本发布后删除。在v4最新,再次,与道路和精确道具。
react-lego示例应用包含完全符合in routes.js on its react-router-4 branch
的代码答案 8 :(得分:19)
这是我提出的最干净的解决方案(React Router v4):
<Route
path="/"
component={props => <MyComponent {...props} foo="lol" />}
/>
MyComponent
仍然有props.match
和props.location
,并且props.foo === "lol"
。
答案 9 :(得分:11)
您还可以使用RouteHandler mixin来避免包装器组件,并且更容易将父状态传递为props:
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);
});
答案 10 :(得分:11)
用无状态功能组件包裹它:
<Router>
<Route
path='/'
component={({children}) =>
<MyComponent myProp={'myVal'}>{children}</MyComponent/>
}/>
</Router>
答案 11 :(得分:11)
您可以通过<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
最终可能会收到真正用于不同组件的道具,具体取决于您的路线配置。这不是一件大事,因为props
是不可变的,但如果两个不同的组件期望一个名为foo
但具有不同值的道具,这可能会有问题。
答案 12 :(得分:9)
在1.0和2.0中,您可以使用createElement
Router
道具来指定创建目标元素的准确程度。 Documentation source
function createWithDefaultProps(Component, props) {
return <Component {...props} myprop="value" />;
}
// and then
<Router createElement={createWithDefaultProps}>
...
</Router>
答案 13 :(得分:5)
您还可以结合使用es6和stateless functions来获得更清晰的结果:
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
}
]
}
答案 14 :(得分:4)
对于react router 2.x。
const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;
并在你的路线......
<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>
确保第3个参数是像{ checked: false }
。
答案 15 :(得分:4)
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()从组件生命周期方法重定向,检查位置等。
希望这有帮助!
答案 16 :(得分:1)
React Router的问题在于它渲染你的组件,因此阻止你传递道具。另一方面,Navigation router允许您渲染自己的组件。这意味着你不必跳过任何箍来传递道具,如下面的代码和随附的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();
答案 17 :(得分:1)
根据Rajesh Naroth的回答,使用带或不带路由器的组件。
{{1}}
或者你可以这样做:
{{1}}
答案 18 :(得分:1)
我已经here回答了这个问题。
以下是将道具传递到路线组件的几种方法。
使用react-router v5,我们可以通过包装一个组件来创建路线,这样我们就可以轻松地将props传递到所需的组件上。
<Route path="/">
<Home name="Sai" />
</Route>
类似地,您可以在v5中使用儿童道具。
<Route path="/" children={ <Home name="Sai" />} />
如果您使用react-router v4,则可以使用渲染道具传递它。
<Route path="/" render={() => <Home name="Sai" />} />
答案 19 :(得分:1)
React Router v5.1 (React >= 16.8) 这样做的方式:
<Route path="/comments">
<Comments myprop="value" />
</Route>
现在,如果您想访问组件内的 Route Props,则可以引用此 solution。在函数组件的情况下,还有另一个钩子 useParams()
在那篇文章中没有提到。
更多参考:React Router v5.1
答案 20 :(得分:0)
对于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'})}
)
}
...
答案 21 :(得分:0)
使用自定义路由组件,可以在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
答案 22 :(得分:0)
这可能是将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}))
}
/>
)
}
答案 23 :(得分:0)
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;
答案 24 :(得分:0)
使用上述解决方案,并且此版本在v3.2.5中有效。
<Route
path="/foo"
component={() => (
<Content
lang="foo"
meta={{
description: lang_foo.description
}}
/>
)}
/>
或
<Route path="/foo">
<Content
lang="foo"
meta={{
description: lang_foo.description
}}
/>
</Route>
答案 25 :(得分:0)
在 react-router-v3 中,我没有找到任何可行的解决方案,所以我做了一个很大的权衡,使用类继承而不是 props。
例如:
class MyComments extends Comments{
constructor(props) {
super(props);
this.myProp = myValue;
}
}
并且,您在 Router 的 MyComments
中使用 component
而没有 props。
然后,您可以使用this.myProp
在componentDidMount()
函数中获取'myValue';