繁体   English   中英

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

[英]react-router - pass props to handler component

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

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

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

更新

从新版本开始,可以直接通过Route组件传递 props,而无需使用 Wrapper。 例如,通过使用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} />} />

代码沙盒示例


旧版本

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

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

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

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

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

代码如下:

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

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

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

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

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

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

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

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

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

如果您需要传递孩子:

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

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

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

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

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

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

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

您还可以使用 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但具有不同值的 prop,这可能会出现问题。

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

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

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

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

希望这可以帮助!

您还可以结合使用 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
      }
    ]
}

对于反应路由器 2.x。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

根据 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 v5.1 (React >= 16.8) 这样做的方式:

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

现在,如果您想访问组件内的Route Props,则可以参考此解决方案 在函数组件的情况下,还有另一个钩子useParams()useParams()文章中没有提到。

更多参考: React Router v5.1

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

使用自定义路由组件,这在 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-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}))
       }
      />
    )
}
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-v3 中,我没有找到任何可行的解决方案,所以我做了一个很大的权衡,使用类继承而不是道具。

例如:

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

并且,您在 Router 的component使用MyComments而不使用 props。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM