简体   繁体   English

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

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

I have the following structure for my React.js application using React Router :我的 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);
});

I want to pass some properties into the Comments component.我想将一些属性传递给Comments组件。

(normally I'd do this like <Comments myprop="value" /> ) (通常我会这样做<Comments myprop="value" />

What's the easiest and right way to do so with React Router?使用 React Router 这样做的最简单和正确的方法是什么?

If you'd rather not write wrappers, I guess you could do this:如果您不想编写包装器,我想您可以这样做:

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

UPDATE更新

Since new release, it's possible to pass props directly via the Route component, without using a Wrapper.从新版本开始,可以直接通过Route组件传递 props,而无需使用 Wrapper。 For example, by using render prop .例如,通过使用render prop

Component:成分:

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

Usage:用法:

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

Codesandbox Example代码沙盒示例


OLD VERSION旧版本

My preferred way is wrap the Comments component and pass the wrapper as a route handler.我的首选方法是包装Comments组件并将包装器作为路由处理程序传递。

This is your example with changes applied:这是您应用更改的示例:

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

Copying from the comments by ciantic in the accepted response:ciantic在接受的回复中复制评论:

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

This is the most graceful solution in my opinion.这是我认为最优雅的解决方案。 It works.有用。 Helped me.帮助过我。

This is the solution from Rajesh , without the inconvenient commented by yuji , and updated for React Router 4.这是来自 Rajesh解决方案,没有yuji 评论的不便,并针对 React Router 4 进行了更新。

The code would be like this:代码如下:

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

Note that I use render instead of component .请注意,我使用render而不是component The reason is to avoid undesired remounting .原因是为了避免 不需要的重新安装 I also pass the props to that method, and I use the same props on the Comments component with the object spread operator (ES7 proposal).我还将props传递给该方法,并且我在 Comments 组件上使用了相同的 props 和对象扩展运算符(ES7 提议)。

Just a follow-up to ColCh's answer.只是对 ColCh 的回答的后续行动。 It is quite easy to abstract the wrapping of a component:抽象组件的包装非常容易:

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

I haven't tested this solution yet so any feedback is important.我还没有测试过这个解决方案,所以任何反馈都很重要。

It's important to note that with this method, any props sent via the Router (such as params) get overwritten / removed.重要的是要注意,使用此方法,通过路由器发送的任何道具(例如参数)都会被覆盖/删除。

You can pass props by passing them to <RouteHandler> (in v0.13.x) or the Route component itself in v1.0;你可以通过将它们传递给<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 })}

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

All child handlers will receive the same set of props - this may be useful or not depending on the circumstance.所有子处理程序都将收到相同的一组道具——这可能有用或没有用,具体取决于情况。

Using ES6 you can just make component wrappers inline:使用 ES6,您可以内联组件包装器:

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

If you need to pass children:如果您需要传递孩子:

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

React-router v4 alpha反应路由器 v4 alpha

now there is a new way, to do this, although very similar to the previous method.现在有一种新方法可以做到这一点,尽管与以前的方法非常相似。

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 This works only in alpha version, and were removed after the v4 alpha release. PS 这仅适用于 alpha 版本,并在 v4 alpha 版本后被删除。 In v4 latest, is once again , with the path and exact props.在最新的 v4 中,再次使用路径和精确道具。

react-lego an example app contains code that does exactly this in routes.js on its react-router-4 branch react-lego一个示例应用程序包含在它的 react-router-4 分支上的 routes.js中执行此操作的代码

Here's the cleanest solution I've come up with (React Router v4):这是我想出的最干净的解决方案(React Router v4):

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

MyComponent still has props.match and props.location , and has props.foo === "lol" . MyComponent仍然有props.matchprops.location ,并且有props.foo === "lol"

Wrap it with a stateless function component:用一个无状态的函数组件包裹它:

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

You could also use the RouteHandler mixin to avoid the wrapper component and more easily pass down the parent's state as props:您还可以使用 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);
});

You can pass in props via the <RouterHandler/> like this:你可以像这样通过<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>
    );
  }
});

The downside of this is you are passing props indiscriminately.这样做的缺点是你不分青红皂白地传递道具。 So Comments may end up receiving props that are really intended for a different component depending on your routes configuration.因此,根据您的路由配置, Comments最终可能会收到真正用于不同组件的道具。 It's not a huge deal since props is immutable, but this can be problematic if two different components are expecting a prop named foo but with different values.这不是什么大问题,因为props是不可变的,但是如果两个不同的组件需要一个名为foo但具有不同值的 prop,这可能会出现问题。

In 1.0 and 2.0 you can use createElement prop of Router to specify how exactly to create your target element.在 1.0 和 2.0 中,您可以使用Router createElement来指定如何准确地创建目标元素。 Documentation source 文档来源

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

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

React Router v 4 solution React Router v 4 解决方案

I stumbled upon this question earlier today, and here is the pattern I use.我今天早些时候偶然发现了这个问题,这是我使用的模式。 Hopefully this is useful to anyone looking for a more current solution.希望这对任何寻找更当前解决方案的人有用。

I'm not sure if this is the best solution, but this is my current pattern for this.我不确定这是否是最好的解决方案,但这是我目前的模式。 I have typically have a Core directory where I keep my commonly used components with their relevant configurations (loaders, modals, etc), and I include a file like this:我通常有一个 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

Then, in the file in question, I'll do the following:然后,在相关文件中,我将执行以下操作:

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

You'll notice I import the default export of my component as humble camel-case, which lets me name the new, location-aware component in CamelCase so I can use it normally.您会注意到我将组件的默认导出导入为不起眼的驼峰式大小写,这让我可以在 CamelCase 中命名新的位置感知组件,以便我可以正常使用它。 Other than the additional import line and the assignment line, the component behaves as expected and receives all its props normally, with the addition of all the route props.除了额外的导入行和分配行之外,组件按预期运行并正常接收其所有道具,并添加了所有路由道具。 Thus, I can happily redirect from component lifecycle methods with this.props.history.push(), check the location, etc.因此,我可以很高兴地使用 this.props.history.push() 从组件生命周期方法重定向,检查位置等。

Hope this helps!希望这可以帮助!

You can also combine es6 and stateless functions to get a much cleaner result:您还可以结合使用 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
      }
    ]
}

For react router 2.x.对于反应路由器 2.x。

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

and in your routes...在你的路线中......

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

make sure the 3rd param is an object like: { checked: false } .确保第三个参数是一个对象,如: { checked: false }

I have answered this already here .我已经在这里回答了这个问题

Here are few ways you can pass props to a route component.这里有几种方法可以将 props 传递给路由组件。

With the react-router v5, we can create routes by wrapping with a component, so that we can easily pass props to the desired component like this.使用 react-router v5,我们可以通过包裹一个组件来创建路由,这样我们就可以像这样轻松地将 props 传递给所需的组件。

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

Similarly, you can use the children prop in v5.同样,您可以在 v5 中使用 children 属性。

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

If you are using react-router v4, you can pass it using the render prop.如果您使用的是 react-router v4,则可以使用 render prop 传递它。

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

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

The problem with the React Router is that it renders your components and so stops you passsing in props. React Router 的问题在于它渲染你的组件,因此阻止你传入 props。 The Navigation router , on the other hand, lets you render your own components.另一方面,导航路由器允许您呈现自己的组件。 That means you don't have to jump through any hoops to pass in props as the following code and accompanying JsFiddle show.这意味着您不必跳过任何箍来传递道具作为以下代码和随附的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();

Use the component with or without router based on Rajesh Naroth answer.根据 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}/>
);

Or your could do it this way:或者你可以这样做:

export const Index = ({foo, route}) => {
  const content = (foo) ? foo : (route) ? route.foo : 'No content found!';
  return <h1>{content}</h1>
};

The React Router v5.1 (React >= 16.8) way of doing this: React Router v5.1 (React >= 16.8) 这样做的方式:

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

Now if you want to access Route Props inside your component then you can refer this solution .现在,如果您想访问组件内的Route Props,则可以参考此解决方案 In case of functional component, there is another hook useParams() that is not mentioned in that post.在函数组件的情况下,还有另一个钩子useParams()useParams()文章中没有提到。

More reference: React Router v5.1更多参考: React Router v5.1

for the react-router 2.5.2,the solution is so easy:对于 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'})}
  )
}
...

Using a custom route component , this is possible in React Router v3.使用自定义路由组件,这在 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>
);

As for the <MyRoute> component code, it should be something like:至于<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;

For more details about the custom route component approach, check out my blog post on the subject: http://marmelab.com/blog/2016/09/20/custom-react-router-component.html有关自定义路由组件方法的更多详细信息,请查看我关于该主题的博客文章: http : //marmelab.com/blog/2016/09/20/custom-react-router-component.html

this is probably the best way to use react-router-dom with a cookie handler这可能是将 react-router-dom 与 cookie 处理程序一起使用的最佳方式

in index.js在 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>
  )
}

and use a cookieCheck并使用 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;

Use the solution like a below and this works in v3.2.5.使用如下解决方案,这适用于 v3.2.5。

<Route
  path="/foo"
  component={() => (
    <Content
      lang="foo"
      meta={{
        description: lang_foo.description
      }}
    />
  )}
/>

or或者

<Route path="/foo">
  <Content
    lang="foo"
    meta={{
      description: lang_foo.description
    }}
  />
</Route>

In react-router-v3, I do NOT find any working solutions, so I make a big trade-off, use class inherit instead of props.在 react-router-v3 中,我没有找到任何可行的解决方案,所以我做了一个很大的权衡,使用类继承而不是道具。

for example:例如:

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

and, you use MyComments in Router's component without props.并且,您在 Router 的component使用MyComments而不使用 props。

then, you can use this.myProp to get 'myValue' in componentDidMount() function;然后,您可以使用this.myPropcomponentDidMount()函数中获取“myValue”;

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

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