react-router – passa gli oggetti di scena al componente handler

Ho la seguente struttura per la mia applicazione React.js usando React Router :

var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var Index = React.createClass({ render: function () { return ( 
Some header
); } }); var routes = ( ); ReactRouter.run(routes, function (Handler) { React.render(, document.body); });

Voglio passare alcune proprietà nel componente Comments .

(normalmente lo farei come )

Qual è il modo più semplice e corretto per farlo con React Router?


AGGIORNAMENTO dalla nuova versione, è ansible passare oggetti di scena direttamente tramite il componente Route , senza usare Wrapper

Ad esempio, utilizzando il puntello di render . Link per reactjs router: https://reacttraining.com/react-router/web/api/Route/render-func

Esempio di codice su codesandbox: https://codesandbox.io/s/z3ovqpmp44

Componente

  class Greeting extends React.Component { render() { const { text, match: { params } } = this.props; const { name } = params; return (  

Greeting page

{text} {name}

); } }

E l’uso

  } /> 

VECCHIA VERSIONE

Il mio modo preferito è racchiudere il componente Comments e passare il wrapper come gestore di instradamento.

Questo è il tuo esempio con le modifiche applicate:

 var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var CommentsWrapper = React.createClass({ render: function () { return (  ); } }); var Index = React.createClass({ render: function () { return ( 
Some header
); } }); var routes = ( ); ReactRouter.run(routes, function (Handler) { React.render(, document.body); });

Se preferisci non scrivere wrapper, immagino che potresti fare questo:

 class Index extends React.Component { constructor(props) { super(props); } render() { return ( 

Index - {this.props.route.foo}

); } } var routes = ( );

Copia dai commenti di ciantic nella risposta accettata:

  ()}/> 

Questa è la soluzione più elegante a mio parere. Funziona. Mi ha aiutato.

Questa è la soluzione di Rajesh , senza l’inconveniente commentato da yuji , e aggiornato per React Router 4.

Il codice sarebbe come questo:

  }/> 

Si noti che utilizzo il render anziché il component . Il motivo è di evitare il riassembly indesiderato . Passo anche gli props di props a quel metodo, e uso gli stessi oggetti di scena sul componente Commenti con l’operatore di diffusione degli oggetti (proposta ES7).

Solo un seguito alla risposta di ColCh. È abbastanza semplice astrarre il wrapping di un componente:

 var React = require('react'); var wrapComponent = function(Component, props) { return React.createClass({ render: function() { return React.createElement(Component, props); } }); };  

Non ho ancora testato questa soluzione, quindi qualsiasi feedback è importante.

È importante notare che con questo metodo, gli oggetti di scena inviati tramite il router (come i parametri) vengono sovrascritti / rimossi.

Puoi passare oggetti di scena passandoli a (in v0.13.x) o al componente Route stesso nella v1.0;

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

(dalla guida all’upgrade all’indirizzo https://github.com/rackt/react-router/releases/tag/v1.0.0 )

Tutti gli handler per bambini riceveranno lo stesso set di oggetti di scena – questo può essere utile o meno a seconda della circostanza.

Usando ES6 puoi semplicemente rendere i wrapper dei componenti in linea:

} >

Se hai bisogno di passare i bambini:

{props.children}} >

React-router v4 alpha

ora c’è un nuovo modo, per fare questo, anche se molto simile al metodo precedente.

 import { Match, Link, Miss } from 'react-router'; import Homepage from './containers/Homepage'; const route = { exactly: true, pattern: '/', title: `${siteTitle} - homepage`, component: Homepage }  } /> 

PS Funziona solo in versione alpha e sono stati rimossi dopo la versione alpha v4. In v4 l’ultima, è ancora una volta, con il percorso e puntelli esatti.

react-lego un’app di esempio contiene codice che fa esattamente questo in routes.js sul suo ramo react-router-4

Ecco la soluzione più pulita che ho trovato (React Router v4):

  } /> 

MyComponent ha ancora props.match e props.location e ha props.foo === "lol" .

Puoi anche utilizzare il mixin RouteHandler per evitare il componente wrapper e passare più facilmente allo stato del genitore come oggetti di scena:

 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 ( 
Some header
{handler}
); } }); var routes = ( ); ReactRouter.run(routes, function (Handler) { React.render(, document.body); });

Puoi passare oggetti di scena tramite questo modo:

 var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var Index = React.createClass({ render: function () { var props = this.props; // or possibly this.state return ( 
Some header
); } });

Il rovescio della medaglia di questo è che stai passando oggetti di scena indiscriminatamente. Quindi i Comments possono finire per ricevere oggetti che sono realmente destinati a un componente diverso a seconda della configurazione dei percorsi. Non è un grosso problema dato che i props sono immutabili, ma questo può essere problematico se due componenti diversi si aspettano un puntello chiamato foo ma con valori diversi.

Avvolgilo con un componente della funzione stateless:

   {children} }/>  

In 1.0 e 2.0 puoi usare createElement prop di Router per specificare esattamente come creare il tuo elemento target. Fonte di documentazione

 function createWithDefaultProps(Component, props) { return ; } // and then  ...  

Puoi anche combinare es6 e funzioni stateless per ottenere un risultato molto più pulito:

 import Dashboard from './Dashboard'; import Comments from './Comments'; let dashboardWrapper = () => , commentsWrapper = () => , index = () => 
Some header
{this.props.children}
; routes = { component: index, path: '/', childRoutes: [ { path: 'comments', component: dashboardWrapper }, { path: 'dashboard', component: commentsWrapper } ] }

Per reactjs router 2.x.

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

e nei tuoi percorsi …

   

assicurati che il terzo param sia un object come: { checked: false } .

React Router v 4 solution

Mi sono imbattuto in questa domanda all’inizio di oggi, ed ecco il modello che uso. Speriamo che questo sia utile a chiunque cerchi una soluzione più attuale.

Non sono sicuro se questa sia la soluzione migliore , ma questo è il mio schema attuale per questo. In genere ho una directory Core in cui mantengo i miei componenti di uso comune con le loro configurazioni rilevanti (caricatori, modali, ecc.) E includo un file come questo:

 import React from 'react' import { Route } from 'react-router-dom' const getLocationAwareComponent = (component) => (props) => (  React.createElement(component, {...routeProps, ...props})}/> ) export default getLocationAwareComponent 

Quindi, nel file in questione, farò quanto segue:

 import React from 'react' import someComponent from 'components/SomeComponent' import { getLocationAwareComponent } from 'components/Core/getLocationAwareComponent' const SomeComponent = getLocationAwareComponent(someComponent) // in render method:  

Noterai che impongo l’esportazione predefinita del mio componente come humble-camel-case, che mi consente di nominare il nuovo componente, in grado di riconoscere la posizione, in CamelCase in modo da poterlo usare normalmente. Oltre alla linea di importazione aggiuntiva e alla linea di assegnazione, il componente si comporta come previsto e riceve tutti i suoi oggetti di scena normalmente, con l’aggiunta di tutti gli oggetti di scena. Quindi, posso tranquillamente redirect dai metodi del ciclo di vita dei componenti con this.props.history.push (), controllare la posizione, ecc.

Spero che questo ti aiuti!

Il problema con React Router è che esegue il rendering dei componenti e quindi impedisce il passsing nei puntelli. Il router di navigazione , d’altra parte, ti permette di rendere i tuoi componenti. Ciò significa che non devi saltare attraverso i cerchi per passare in oggetti di scena come il seguente codice e lo spettacolo JsFiddle che accompagna.

 var Comments = ({myProp}) => 
{myProp}
; var stateNavigator = new Navigation.StateNavigator([ {key:'comments', route:''} ]); stateNavigator.states.comments.navigated = function(data) { ReactDOM.render( , document.getElementById('content') ); } stateNavigator.start();

Utilizzare il componente con o senza router in base alla risposta di 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 ( 

Index - {foo}

); } } var routes = ( );

Oppure potresti farlo in questo modo:

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

{content}

};

per il react-router 2.5.2, la soluzione è così semplice:

  //someConponent ... render:function(){ return ( 

This is the parent component who pass the prop to this.props.children

{this.props.children && React.cloneElement(this.props.children,{myProp:'value'})} ) } ...

Utilizzando un componente di instradamento personalizzato , ciò è ansible in React Router v3.

 var Dashboard = require('./Dashboard'); var Comments = require('./Comments'); var routes = (     ); 

Per quanto riguarda il codice del componente , dovrebbe essere qualcosa del tipo:

 import React from 'react'; import { Route } from 'react-router'; import { createRoutesFromReactChildren } from 'react-router/lib//RouteUtils'; const MyRoute = () => 
<MyRoute> elements are for configuration only and should not be rendered
; MyRoute.createRouteFromReactElement = (element, parentRoute) => { const { path, myprop } = element.props; // dynamically add crud route const myRoute = createRoutesFromReactChildren( , parentRoute )[0]; // higher-order component to pass myprop as resource to components myRoute.component = ({ children }) => (
{React.Children.map(children, child => React.cloneElement(child, { myprop }))}
); return myRoute; }; export default MyRoute;

Per ulteriori dettagli sull’approccio del componente del percorso personalizzato, consulta il mio post sul blog: http://marmelab.com/blog/2016/09/20/custom-react-router-component.html