web-dev-qa-db-ger.com

reakt-Router - Requisiten an die Handler-Komponente übergeben

Ich habe die folgende Struktur für meine React.js-Anwendung mit 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);
});

Ich möchte einige Eigenschaften an die Comments-Komponente übergeben. 

(Normalerweise würde ich das wie <Comments myprop="value" /> machen)

Was ist der einfachste und richtige Weg, um mit React Router zu arbeiten?

278
Kosmetika

UPDATE seit der neuen Version ist es möglich, Requisiten direkt über die Route-Komponente zu übergeben, ohne einen Wrapper zu verwenden 

Zum Beispiel mit render prop. Link zum reagierenden Router: https://reacttraining.com/react-router/web/api/Route/render-func

Codebeispiel bei codesandbox: https://codesandbox.io/s/z3ovqpmp44

Komponente

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

Und Verwendung

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

ALTE VERSION

Meine bevorzugte Methode besteht darin, die Comments-Komponente einzuhüllen und den Wrapper als Routenhandler zu übergeben.

Dies ist Ihr Beispiel mit den vorgenommenen Änderungen:

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

Wenn Sie lieber keine Wrapper schreiben möchten, könnten Sie folgendes tun

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

Kopieren aus den Kommentaren von ciantic in der akzeptierten Antwort: 

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

Dies ist meiner Meinung nach die eleganteste Lösung. Es klappt. Half mir.

111
Rajesh Naroth

Dies ist die -Lösung von Rajesh , ohne die unbequemen , die von yuji kommentiert und für React Router 4 aktualisiert wurden.

Der Code würde so aussehen:

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

Beachten Sie, dass ich render anstelle von component verwende. Der Grund ist, unerwünschtes Remounting zu vermeiden. Ich übergebe auch die Variable props an dieser Methode und verwende dieselben Requisiten für die Kommentarkomponente mit dem Objekt-Spread-Operator (Vorschlag von ES7).

50
Daniel Reina

Nur eine Folge der Antwort von ColCh. Die Verpackung einer Komponente lässt sich leicht abstrahieren:

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

Ich habe diese Lösung noch nicht getestet, daher ist jedes Feedback wichtig.

Es ist wichtig zu beachten, dass bei dieser Methode alle über den Router gesendeten Requisiten (z. B. Params) überschrieben/entfernt werden.

43
sigmus

Sie können Requisiten übergeben, indem Sie sie an <RouteHandler> (in v0.13.x) oder an die Route-Komponente selbst in v1.0 übergeben.

// v0.13.x
<RouteHandler/>
<RouteHandler someExtraProp={something}/>

// v1.0
{this.props.children}
{React.cloneElement(this.props.children, {someExtraProp: something })}

(aus der Upgrade-Anleitung unter https://github.com/rackt/react-router/releases/tag/v1.0.0 )

Alle Child-Handler erhalten die gleichen Requisiten - dies kann je nach den Umständen nützlich sein oder nicht.

30
cachvico

Mit ES6 können Sie Komponenten-Wrapper einfach inline erstellen:

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

Wenn Sie Kinder übergeben müssen:

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

23
Nick

Reakt-Router v4 alpha

jetzt gibt es einen neuen Weg, dies zu tun, obwohl er der vorherigen Methode sehr ähnlich ist.

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. Dies funktioniert nur in der Alpha-Version und wurde nach der v4-Alpha-Version entfernt. In v4 spätestens ist es wieder einmal mit dem Weg und den genauen Requisiten.

reag-lego Eine Beispiel-App enthält Code, der genau dies in routes.js auf dem reag-router-4-Zweig tut

22
peter.mouland

Hier ist die sauberste Lösung, die ich mir vorgestellt habe (React Router v4):

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

MyComponent hat noch props.match und props.location und props.foo === "lol".

19
cgenco

Umschließen Sie es mit einer statuslosen Funktionskomponente:

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

Sie können Requisiten über den <RouterHandler/> wie folgt übergeben:

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

Der Nachteil ist, dass Sie wahllos Requisiten übergeben. Comments kann am Ende Requisiten erhalten, die abhängig von der Konfiguration Ihrer Routen für eine andere Komponente bestimmt sind. Es ist keine große Sache, da props unveränderlich ist, aber dies kann problematisch sein, wenn zwei verschiedene Komponenten eine Requisite namens foo erwarten, die jedoch unterschiedliche Werte hat.

11
Meistro

Sie können auch das RouteHandler-Mixin verwenden, um die Wrapper-Komponente zu vermeiden und den Status des übergeordneten Elements einfacher als Requisiten zu übergeben:

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

In 1.0 und 2.0 können Sie createElement prop von Router verwenden, um anzugeben, wie genau Ihr Zielelement erstellt werden soll. Quelle der Dokumentation

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

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

Sie können auch die Funktionen es6 und stateless kombinieren, um ein wesentlich saubereres Ergebnis zu erhalten:

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
      }
    ]
}
5
Zhiwei Huang

Für den Router 2.x reagieren.

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

und auf deinen Routen ...

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

stellen Sie sicher, dass der 3. Parameter ein Objekt wie folgt ist: { checked: false }.

4
holyxiaoxin

React Router v 4 solution

Ich bin heute schon früher auf diese Frage gestoßen, und hier ist das Muster, das ich benutze. Hoffentlich ist dies nützlich für alle, die nach einer aktuelleren Lösung suchen.

Ich bin nicht sicher, ob dies die beste Lösung ist, aber dies ist mein aktuelles Muster dafür. Ich habe normalerweise ein Core-Verzeichnis, in dem ich meine häufig verwendeten Komponenten mit ihren relevanten Konfigurationen (Loader, Modals usw.) verwalte, und füge eine Datei wie die folgende hinzu:

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

Dann mache ich in der fraglichen Datei Folgendes:

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

Sie werden feststellen, dass ich den Standardexport meiner Komponente als bescheidene Kameltasche importiere, sodass ich die neue ortsbezogene Komponente in CamelCase benennen kann, damit ich sie normal verwenden kann. Abgesehen von der zusätzlichen Import- und Zuweisungszeile verhält sich die Komponente wie erwartet und empfängt alle Requisiten normal, wobei alle Routen-Requisiten hinzugefügt werden. Auf diese Weise kann ich mithilfe von this.props.history.Push () problemlos von Komponentenlebenszyklusmethoden umleiten, den Speicherort überprüfen usw.

Hoffe das hilft!

4
Chris

Verwenden Sie die Komponente mit oder ohne Router basierend auf der Antwort von 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}/>
);

Oder Sie könnten es so machen:

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

Das Problem mit dem React Router besteht darin, dass er Ihre Komponenten rendert und Sie so daran hindert, Requisiten zu übergeben. Mit dem Navigation-Router können Sie dagegen Ihre eigenen Komponenten rendern. Das bedeutet, dass Sie nicht durch einen Reifen springen müssen, um Requisiten als folgenden Code und die dazugehörige JsFiddle show zu übergeben.

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();
1
graham mendick

Bei Verwendung einer benutzerdefinierten Routenkomponente ist dies in React Router v3 möglich. 

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

Der <MyRoute>-Komponentencode sollte etwa wie folgt lauten:

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;

Weitere Informationen zum Ansatz für benutzerdefinierte Routenkomponenten finden Sie in meinem Blogeintrag zum Thema: http://marmelab.com/blog/2016/09/20/custom-react-router-component.html

0

für den Reakt-Router 2.5.2 ist die Lösung so einfach:

    //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'})}
  )
}
...
0
min may
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;
0
nik.ss

dies ist wahrscheinlich der beste Weg, um reaktiver Router mit einem Cookie-Handler zu verwenden 

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

und verwenden Sie einen 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}))
       }
      />
    )
}
0
Snivio