[Javascript] react-router - passa gli oggetti di scena al componente handler


Answers

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

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

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

Voglio passare alcune proprietà nel componente Comments .

(normalmente lo farei come <Comments myprop="value" /> )

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




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 (
      <h1>
        Index - {foo}
      </h1>
    );
  }
}

var routes = (
  <Route path="/" foo="bar" component={Index}/>
);

Oppure potresti farlo in questo modo:

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



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

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

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




Avvolgilo con un componente della funzione stateless:

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



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
  }

<Match { ...route } render={(props) => <route.component {...props} />} />

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




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

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



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) => (
  <Route render={(routeProps) => 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:
<SomeComponent someProp={value} />

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 reindirizzare dai metodi del ciclo di vita dei componenti con this.props.history.push (), controllare la posizione, ecc.

Spero che questo ti aiuti!




Utilizzando un componente di instradamento personalizzato , ciò è possibile in 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>
);

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

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;

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




Puoi passare oggetti di scena tramite <RouterHandler/> 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 (
        <div>
            <header>Some header</header>
            <RouteHandler {...props} />
        </div>
    );
  }
});

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.




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

Il codice sarebbe come questo:

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

Si noti che utilizzo il render anziché il component . Il motivo è di evitare il rimontaggio 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).