364

我的 React.js 应用程序使用React Router具有以下结构:

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

4

26 回答 26

266

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

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}/>
);
于 2015-09-24T12:56:32.520 回答
191

更新

自新版本以来,可以直接通过Route组件传递道具,而无需使用 Wrapper。例如,通过使用renderprop

零件:

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);
});
于 2015-01-09T20:18:54.090 回答
125

从ciantic在接受的回复中的评论中复制:

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

这是我认为最优雅的解决方案。有用。帮助过我。

于 2016-08-18T20:44:34.023 回答
62

这是来自 Rajesh 的解决方案,没有yuji 评论的不便,并针对 React Router 4 进行了更新。

代码将是这样的:

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

请注意,我使用render而不是component. 原因是为了避免不必要的重新安装。我还将 传递props给该方法,并在 Comments 组件上使用相同的道具和对象扩展运算符(ES7 提议)。

于 2017-04-08T19:45:08.240 回答
45

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

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

请务必注意,使用此方法,通过路由器发送的任何道具(例如参数)都会被覆盖/删除。

于 2015-04-18T17:25:25.580 回答
31

您可以通过将道具传递给<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的升级指南)

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

于 2015-07-24T06:05:36.707 回答
24

使用 ES6,您可以将组件包装器内联:

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

如果您需要传递孩子:

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

于 2016-08-11T23:40:39.517 回答
23

反应路由器 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中执行此操作的代码

于 2016-09-15T08:09:44.690 回答
21

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

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

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

于 2017-03-20T00:04:23.633 回答
12

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

<Router>
  <Route 
    path='/' 
    component={({children}) => 
      <MyComponent myProp={'myVal'}>{children}</MyComponent/>
    }/>
</Router>
于 2016-05-14T21:35:22.657 回答
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);
});
于 2015-01-27T21:44:59.257 回答
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但具有不同值的道具,这可能会出现问题。

于 2015-03-27T19:10:04.390 回答
9

在 1.0 和 2.0 中,您可以使用createElementprop ofRouter来指定如何准确地创建您的目标元素。文档来源

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

// and then    
<Router createElement={createWithDefaultProps}>
    ...
</Router>
于 2016-02-11T10:42:42.120 回答
7

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() 从组件生命周期方法重定向,检查位置等。

希望这可以帮助!

于 2017-06-22T20:21:19.303 回答
5

您还可以结合 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
      }
    ]
}
于 2015-11-30T07:09:58.157 回答
5

我已经在这里回答了这个问题。

这里有几种方法可以将 props 传递给路由组件。

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

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

同样,您可以使用 v5 中的 children 道具。

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

如果您使用的是 react-router v4,则可以使用 render prop 传递它。

旁注- 引用 React 路由器children-func doc

有时您需要渲染路径是否与位置匹配。在这些情况下,您可以使用功能 children 道具。它的工作原理与 render 完全一样,只是无论是否匹配都会被调用。

<Route path="/" render={() => <Home name="Sai" />} />

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

于 2020-08-29T01:20:16.113 回答
3

对于反应路由器 2.x。

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

在你的路线中......

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

确保第三个参数是一个对象,如:{ checked: false }.

于 2016-12-14T10:04:58.567 回答
1

React Router 的问题在于它会渲染你的组件,因此会阻止你传入 props。另一方面,导航路由器允许您渲染自己的组件这意味着您不必像下面的代码和随附的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();
于 2016-06-20T10:42:46.997 回答
1

根据 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>
};
于 2017-01-02T13:23:39.923 回答
1

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

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

现在,如果您想访问组件内的Route Props,则可以参考此解决方案。如果是功能组件,那篇useParams()文章中没有提到另一个钩子。

更多参考:React Router v5.1

于 2020-12-20T08:15:03.030 回答
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'})}
  )
}
...
于 2016-08-11T03:35:54.737 回答
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>&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

于 2016-09-20T15:53:25.407 回答
0

这可能是使用带有 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>
  )
}

并使用 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}))
       }
      />
    )
}
于 2018-11-30T19:19:17.443 回答
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;
于 2019-07-04T00:23:00.070 回答
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>
于 2019-12-04T08:00:33.240 回答
0

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

例如:

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

并且,您在没有道具MyComments的路由器中使用。component

然后,您可以使用this.myProp在函数中获取“myValue” componentDidMount()

于 2021-06-28T07:09:03.030 回答