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路由器最简单和正确的方法是什么?

290064 次浏览

更新

自新版本发布以来,可以直接通过Route组件传递道具,而不使用Wrapper。例如,通过使用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} />} />

< a href = " https://codesandbox。io/s/z3ovqpmp44" rel="noreferrer">代码框示例< a> . io/s/z3ovqpmp44" rel="noreferrer">代码框示例


旧版本

我的首选方法是包装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);
});

你也可以使用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);
});

你可以像这样通过<RouterHandler/>传入props:

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但值不同的道具,这就会出现问题。

只是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})}/>

我还没有测试这个解决方案,所以任何反馈都很重要。

需要注意的是,使用这种方法,任何通过Router发送的道具(比如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)

所有子处理程序都将收到相同的一组道具——这可能有用,也可能没用,取决于具体情况。

如果你不想写包装器,我想你可以这样做:

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}/>
);

你也可以结合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
}
]
}

在1.0和2.0中,可以使用RoutercreateElement prop来指定如何确切地创建目标元素。文档来源

function createWithDefaultProps(Component, props) {
return <Component {...props} myprop="value" />;
}


// and then
<Router createElement={createWithDefaultProps}>
...
</Router>

用一个无状态的函数组件包装它:

<Router>
<Route
path='/'
component={({children}) =>
<MyComponent myProp={'myVal'}>{children}</MyComponent/>
}/>
</Router>

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();

对于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'})}
)
}
...

使用ES6,你可以让组件包装内联:

<Route path="/" component={() => <App myProp={someValue}/>} >

如果你需要通过孩子:

<Route path="/" component={(props) => <App myProp={someValue}>{props.children}</App>} >

在接受的响应中复制ciantic的注释:

<Route path="comments" component={() => (<Comments myProp="value" />)}/>

在我看来,这是最优雅的解决办法。它的工作原理。帮助了我。

React-router v4 α

现在有了一种新的方法,尽管和之前的方法很相似。

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} />} />

附注:这只适用于alpha版本,并且在v4 alpha发布后被删除。在v4 latest中,同样是带有路径和精确props的。

react-lego一个示例应用程序包含的代码正是这样做的在routes.js的react-router-4分支中

使用自定义路由组件,这在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>&lt;MyRoute&gt; 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

对于react路由器2.x。

const WrappedComponent = (Container, propsToPass, { children }) => <Container {...propsToPass}>{children}</Container>;

在你的路线上…

<Route path="/" component={WrappedComponent.bind(null, LayoutContainer, { someProp })}>
</Route>

确保第3个参数是一个类似{ checked: false }的对象。

根据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>
};

这是我想出的最干净的解决方案(React Router v4):

<Route
path="/"
component={props => <MyComponent {...props} foo="lol" />}
/>

MyComponent仍然有props.matchprops.location,并且有props.foo === "lol"

这是拉杰什的解决方案,没有不方便的yuji评论,并为React Router 4更新。

代码是这样的:

<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>

注意,我使用了render而不是component。原因是为了避免不受欢迎的卸载。我还将props传递给该方法,并在Comments组件上使用对象展开操作符(ES7建议)。

反应路由器v 4解决方案

今天早些时候我偶然发现了这个问题,下面是我使用的模式。希望这对那些正在寻找最新解决方案的人有用。

我不确定这是否是最好的解决方案,但这是我目前的模式。我通常有一个核心目录,我保存我常用的组件及其相关配置(加载器,模态等),我包括一个这样的文件:

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} />

您会注意到我将组件的默认导出导入为humble camel-case,这让我可以在CamelCase中命名新的位置感知组件,以便正常使用它。除了额外的导入行和赋值行之外,组件的行为与预期一致,并正常接收它的所有道具,并添加了所有路由道具。因此,我可以愉快地使用this.props.history.push()重定向组件生命周期方法,检查位置等。

希望这能有所帮助!

这可能是在cookie处理程序中使用react-router-dom的最佳方式

在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>
)
}

并使用cookie检查

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}))
}
/>
)
}
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;

使用如下所示的解决方案,它可以在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>

我已经回答了这个在这里

下面是几种将道具传递给路由组件的方法。

使用react-router v5,我们可以通过封装组件来创建路由,这样我们就可以像这样轻松地将道具传递给所需的组件。

<Route path="/">
<Home name="Sai" />
</Route>

类似地,您可以在v5中使用子道具。

<Route path="/" children={ <Home name="Sai" />} />

如果您正在使用react-router v4,您可以使用渲染道具传递它。

边注 -引用React路由器children-func医生

有时你需要渲染路径是否匹配位置或 不是。在这些情况下,您可以使用函数child prop。它的工作原理 和渲染完全一样,除了它会被调用是否有

.匹配与否
<Route path="/" render={() => <Home name="Sai" />} />

(最初发布于https://reactgo.com/react-router-pass-props/)

React路由器v5.1 (React >= 16.8)这样做的方式:

<Route path="/comments">
<Comments myprop="value" />
</Route>

现在,如果你想在你的组件中访问路线的道具,那么你可以引用这个解决方案。对于函数组件,还有另一个钩子useParams(),在那篇文章中没有提到。

更多参考:React Router v5.1 < / > < / p >

在react-router-v3中,我没有找到任何工作解决方案,所以我做了一个很大的权衡,使用类继承而不是道具。

例如:

class MyComments extends Comments{
constructor(props) {
super(props);
this.myProp = myValue;
}
}

并且,你在路由器的component中使用MyComments而不带道具。

然后,你可以使用this.myPropcomponentDidMount()函数中获取'myValue';