首页 文章

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

提问于
浏览
267

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

21 回答

  • 22

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

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

    如果你需要传递孩子:

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

  • 18

    这可能是使用react-handler-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}))
           }
          />
        )
    }
    
  • 111

    使用 custom route component ,可以在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

  • 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)都会被覆盖/删除 .

  • 252

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

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

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

  • 1

    React Router v 4 solution

    我今天早些时候偶然发现了这个问题,这是我使用的模式 . 希望这对寻求更新解决方案的任何人都有用 .

    我不确定这是否是最佳解决方案,但这是我目前的模式 . 我通常有一个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()从组件生命周期方法重定向,检查位置等 .

    希望这可以帮助!

  • 0

    在1.0和2.0中,您可以使用 createElementRouter 来指定创建目标元素的确切方式 . Documentation source

    function createWithDefaultProps(Component, props) {
        return <Component {...props} myprop="value" />;
    }
    
    // and then    
    <Router createElement={createWithDefaultProps}>
        ...
    </Router>
    
  • 11

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

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

    react-lego示例应用程序包含完全符合此功能的代码in routes.js on its react-router-4 branch

  • 11

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

    这是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组件上使用相同的props .

  • 5

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

    所有儿童处理程序都将收到相同的道具 - 根据具体情况,这可能有用或不有用 .

  • 115

    对于路由器2.x.

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

    在你的路线......

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

    确保第3个参数是一个像这样的对象: { checked: false } .

  • 1

    您还可以使用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);
    });
    
  • 4

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

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

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

    例如,通过使用 render prop . 反应路由器的链接: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>
                );
            }
        }
    

    和用法

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

    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);
    });
    
  • 0

    您可以通过 <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 但具有不同值的道具,则这可能会有问题 .

  • 30

    您还可以组合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
          }
        ]
    }
    
  • 9

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

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

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

  • 4

    React路由器的问题在于它渲染你的组件,因此阻止你传递道具 . 另一方面,Navigation router允许您渲染自己的组件 . 这意味着您不必跳过任何箍来传递道具,如下面的代码和随附的JsFiddle show .

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

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

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

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

相关问题