react-router - 将props传递给处理程序组件

Kos*_*ika 299 javascript properties reactjs 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);
});
Run Code Online (Sandbox Code Playgroud)

我想将一些属性传递给Comments组件.

(通常我会这样做<Comments myprop="value" />)

使用React Router,最简单,最正确的方法是什么?

Tho*_*s E 257

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

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}/>
);
Run Code Online (Sandbox Code Playgroud)

  • 十分感谢!如果有人想知道,foo属性将在您的组件中可用:this.props.route.foo (12认同)
  • 这是一个正确的答案.在react-router 1.0中,您可以在组件中获得`route` plain对象.以下是github问题的答案:https://github.com/rackt/react-router/issues/615#issuecomment-100432086 (11认同)
  • 这个可以设置为正确答案以避免混淆吗? (8认同)
  • 这是我正在寻找的简单答案.其他技术可行,但需要10倍的代码量.适用于v1.0.x. 我能看到的唯一缺点是,如果您打算在使用和不使用路由器容器的情况下使用相同的组件.但对我来说,我的所有顶级组件都与路由一对一映射. (4认同)
  • 不!请参阅Rajesh Naroth真正解决方案的答案:) (2认同)
  • **this.props.route** 在 v4 中不存在。请参阅下面的[此](http://stackoverflow.com/a/43299633/253576)响应,以获取对我有用的答案。他使用的代码记录在[此处](https://github.com/ReactTraining/react-router/issues/4627)和[此处](https://github.com/ReactTraining/react-router/commit/45649fd3cc6fbe4c5b89c3d0506f8f076c3fa6ed #commitcomment-20902957)。 (2认同)

Col*_*lCh 139


自新版本更新后,可以直接通过Route组件传递道具,而无需使用Wrapper

例如,通过使用render道具.链接到反应路由器:https://reacttraining.com/react-router/web/api/Route/render-func

在codesandbox的代码示例:https://codesandbox.io/s/z3ovqpmp44

零件

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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

和用法

<Route path="/greeting/:name" render={(props) => <Greeting text="Hello, " {...props} />} />
Run Code Online (Sandbox Code Playgroud)

旧版

我首选的方法是包装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);
});
Run Code Online (Sandbox Code Playgroud)

  • 我遇到了同样的问题,但是这个解决方案不会很快变得冗长吗? (57认同)
  • 我永远不会同意创建额外的组件只是为了传递属性是"首选方式".它是冗长,复杂,容易出错的,并且在各种可想象的方面都是明显错误的.它可能是路由器允许的唯一方式,但称其为"首选"是一个延伸.首选谁? (32认同)
  • 你可以添加一个无状态组件语法(只是lambda),它非常简短`<Route path ="comments"component = {()=>(<Comments myProp ="value"/>)} />` (27认同)
  • 同意captDaylight,它变得冗长.宁愿用更好的方法来处理这个问题! (8认同)
  • @mattiashallstrom IMO,1.0中更好的方法是简单地将属性添加到路由中.请参阅Thomas E的回答. (6认同)

小智 111

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

<Route path="comments" component={() => (<Comments myProp="value" />)}/>
Run Code Online (Sandbox Code Playgroud)

在我看来,这是最优雅的解决方案.有用.帮助过我.

  • 它就像一个匿名的包装器,因此所有注入的道具(例如位置)都会被遗漏.一个人必须手动传递道具,如`component = {(props)=>(<Comments myProp ="value"location = {props.location} />)}`但这一切都变得混乱 (11认同)
  • 从React-Router 4开始,如果你提供内联函数,你会得到很多不受欢迎的重新安装.对于内联渲染,请使用渲染道具.[链接到文档](https://reacttraining.com/react-router/web/api/Route/component) (7认同)
  • @yuji为了不让它变得太混乱,可以这样做: `component={(props) =&gt; (&lt;Comments {...props} myProp="value" /&gt;)}` 来维护注入的 props (2认同)

Dan*_*ina 54

这是来自Rajesh解决方案,没有由yuji评论的不便,并为React Router 4更新.

代码如下:

<Route path="comments" render={(props) => <Comments myProp="value" {...props}/>}/>
Run Code Online (Sandbox Code Playgroud)

请注意,我使用render而不是component.原因是避免不希望的重新安装.我也传递props给那个方法,并且我使用对象扩展运算符(ES7提议)在Comments组件上使用相同的道具.


sig*_*mus 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})}/>
Run Code Online (Sandbox Code Playgroud)

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

重要的是要注意,使用此方法,通过路由器发送的任何道具(例如params)都会被覆盖/删除.

  • 如果你需要来自路由器的查询和参数,那么这样的东西将起作用:`return React.createElement(Component,_.assign({},this.props,props));`(这个使用_ .assign组成组合对象......当然可以使用其他方法). (3认同)
  • 您可能也希望传递孩子.| var wrapComponent = function(Component,props){return React.createClass({render:function(){return React.createElement(Component,props,this.props.children);}}); }; (2认同)

cac*_*ico 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 })}
Run Code Online (Sandbox Code Playgroud)

(来自https://github.com/rackt/react-router/releases/tag/v1.0.0的升级指南)

所有儿童操作员都将获得相同的道具 - 根据具体情况,这可能有用或不有用.

  • 这显然是文档目标的最佳答案,但我也同意manu可以编写它以更好地展示使用.更具体的问题代码如下:`React.cloneElement(this.props.children,{myprop:"value"})`或`React.cloneElement(this.props.children,{myprop:this.props.myprop })等 (2认同)

Nic*_*ick 23

使用ES6,您可以直接制作组件包装器:

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

如果你需要传递孩子:

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

  • 正如[@dgrcode answer](/sf/answers/3030974341/)指出的那样,你应该使用`render`而不是`component` (2认同)

pet*_*and 22

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} />} />
Run Code Online (Sandbox Code Playgroud)

PS这仅适用于alpha版本,并在v4 alpha版本发布后删除.在v4最新,再次,与道路和精确道具.

react-lego示例app包含在react-router-4分支上的routes.js中完成此操作的代码


cge*_*nco 19

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

<Route
  path="/"
  component={props => <MyComponent {...props} foo="lol" />}
/>
Run Code Online (Sandbox Code Playgroud)

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


jul*_*jul 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);
});
Run Code Online (Sandbox Code Playgroud)

  • 奇怪的是,官方文档中没有提到这一点. (2认同)

Mei*_*tro 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>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

这样做的缺点是你不分青红皂白地传递道具.因此Comments,根据您的路线配置,最终可能会收到真正用于不同组件的道具.这不是一件props大事,因为它是不可变的,但如果两个不同的组件期望一个名为foo但具有不同值的道具,这可能会有问题.

  • 我猜Flux会避免将状态从父App发送到路由.我得到了上面的代码,但它并不明确,所以隐藏的majic是丑陋的,不容易追踪和跟踪正在发生的事情. (2认同)
  • [传播操作员解释](https://gist.github.com/sebmarkbage/07bbe37bc42b6d4aef81#whats-with-the-weird--notation).这不是明确的,但是,因为你传递的是不可变的道具,所以这不是最糟糕的事情. (2认同)

mg7*_*g74 11

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

<Router>
  <Route 
    path='/' 
    component={({children}) => 
      <MyComponent myProp={'myVal'}>{children}</MyComponent/>
    }/>
</Router>
Run Code Online (Sandbox Code Playgroud)


And*_*lov 9

在1.0和2.0中,您可以使用createElementprop Router来指定创建目标元素的确切方式.文档来源

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

// and then    
<Router createElement={createWithDefaultProps}>
    ...
</Router>
Run Code Online (Sandbox Code Playgroud)


sai*_*amr 6

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

您可以通过以下几种方式将 props 传递给路由组件。

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

<Route path="/">
    <Home name="Sai" />
</Route>
Run Code Online (Sandbox Code Playgroud)

同样,您可以在 v5 中使用 Children 属性。

<Route path="/" children={ <Home name="Sai" />} />
Run Code Online (Sandbox Code Playgroud)

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

旁注- 引用 React router Children-func 文档

有时您需要渲染路径是否与位置匹配。在这些情况下,您可以使用 Children 属性函数。它的工作方式与渲染完全相同,只是无论是否匹配都会调用它。

<Route path="/" render={() => <Home name="Sai" />} />
Run Code Online (Sandbox Code Playgroud)

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


小智 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
      }
    ]
}
Run Code Online (Sandbox Code Playgroud)


小智 5

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
Run Code Online (Sandbox Code Playgroud)

然后,在有问题的文件中,执行以下操作:

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} />
Run Code Online (Sandbox Code Playgroud)

您会注意到我将组件的默认导出导入为驼峰式的情况,这使我可以在CamelCase中命名新的位置感知组件,因此我可以正常使用它。除了附加的导入线和分配线以外,该组件的行为与预期的一样,并正常添加所有路径道具,并添加了所有路径道具。因此,我可以很高兴地使用this.props.history.push()从组件生命周期方法重定向,检查位置等。

希望这可以帮助!