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

时间:2015-01-09 16:14:21

标签: 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);
});

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

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

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

26 个答案:

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

Codesandbox Example


OLD VERSION

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

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

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.matchprops.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" />} />

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

答案 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>&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

答案 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.myPropcomponentDidMount()函数中获取'myValue';