react-router - pasar accesorios al componente del controlador

332
Kosmetika 2015-01-10 06:14.

Tengo la siguiente estructura para mi aplicación 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);
});

Quiero pasar algunas propiedades al Commentscomponente.

(normalmente haría esto como <Comments myprop="value" />)

¿Cuál es la forma más fácil y correcta de hacerlo con React Router?

24 answers

167
ColCh 2015-01-10 10:18.

ACTUALIZAR

Desde la nueva versión, es posible pasar accesorios directamente a través del Routecomponente, sin usar un Wrapper. Por ejemplo, usando renderprop .

Componente:

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

Uso:

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

Ejemplo de Codesandbox


VERSIÓN ANTIGUA

Mi forma preferida es envolver el Commentscomponente y pasar el contenedor como controlador de ruta.

Este es su ejemplo con los cambios aplicados:

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);
});
261
Thomas E 2015-09-25 02:56.

Si prefieres no escribir envoltorios, supongo que podrías hacer esto:

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}/>
);
116
Rajesh Naroth 2016-08-19 10:44.

Copiando de los comentarios de ciantic en la respuesta aceptada:

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

Esta es la solución más elegante en mi opinión. Funciona. Me ayudó.

60
Daniel Reina 2017-04-09 09:45.

Esta es la solución de Rajesh , sin los inconvenientes react-router - pasar accesorios al componente del controlador , y actualizada para React Router 4.

El código sería así:

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

Tenga en cuenta que utilizo en renderlugar de component. El motivo es evitar un montaje no deseado . También paso el propsa ese método, y uso los mismos accesorios en el componente Comentarios con el operador de extensión de objetos (propuesta de ES7).

44
sigmus 2015-04-19 07:25.

Solo un seguimiento de la respuesta de ColCh. Es bastante fácil abstraer la envoltura de un componente:

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

Todavía no he probado esta solución, por lo que cualquier comentario es importante.

Es importante tener en cuenta que con este método, cualquier accesorio enviado a través del enrutador (como params) se sobrescribe / elimina.

31
cachvico 2015-07-24 20:05.

Puede pasar accesorios pasándolos a <RouteHandler>(en v0.13.x) o al propio componente de ruta en v1.0;

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

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

(de la guía de actualización en https://github.com/rackt/react-router/releases/tag/v1.0.0 )

Todos los cuidadores de niños recibirán el mismo conjunto de accesorios; esto puede ser útil o no, según las circunstancias.

24
Nick 2016-08-12 13:40.

Con ES6, puede hacer envoltorios de componentes en línea:

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

Si necesita pasar niños:

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

23
peter.mouland 2016-09-15 22:09.

React-router v4 alpha

ahora hay una nueva forma de hacer esto, aunque muy similar al método anterior.

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

PD: Esto solo funciona en la versión alfa y se eliminó después de la versión alfa v4. En la última v4, es una vez más, con la ruta y los accesorios exactos.

react-lego, una aplicación de ejemplo contiene código que hace exactamente esto en route.js en su rama react-router-4

20
cgenco 2017-03-20 14:04.

Aquí está la solución más limpia que he encontrado (React Router v4):

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

MyComponenttodavía tiene props.matchy props.location, y tiene props.foo === "lol".

12
mg74 2016-05-15 11:35.

Envuélvalo con un componente de función sin estado:

<Router>
  <Route 
    path='/' 
    component={({children}) => 
      <MyComponent myProp={'myVal'}>{children}</MyComponent/>
    }/>
</Router>
11
jul 2015-01-28 11:44.

También puede usar el mixin RouteHandler para evitar el componente contenedor y pasar más fácilmente el estado del padre como accesorios:

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
Meistro 2015-03-28 09:10.

Puede pasar accesorios a través de la <RouterHandler/>siguiente manera:

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

La desventaja de esto es que estás pasando accesorios indiscriminadamente. Por Commentslo tanto, puede terminar recibiendo accesorios que realmente están destinados a un componente diferente según la configuración de sus rutas. No es un gran problema ya que propses inmutable, pero esto puede ser problemático si dos componentes diferentes esperan un prop con nombre foopero con valores diferentes.

9
Andrew Khmylov 2016-02-12 00:42.

En 1.0 y 2.0 puede usar createElementprop of Routerpara especificar exactamente cómo crear su elemento de destino. Fuente de documentación

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

// and then    
<Router createElement={createWithDefaultProps}>
    ...
</Router>
7
Chris 2017-06-23 10:21.

Solución React Router v 4

Me topé con esta pregunta hoy y este es el patrón que utilizo. Con suerte, esto es útil para cualquiera que busque una solución más actual.

No estoy seguro de si esta es la mejor solución, pero este es mi patrón actual para esto. Normalmente tengo un directorio Core donde guardo mis componentes de uso común con sus configuraciones relevantes (cargadores, modales, etc.), e incluyo un archivo como este:

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

Luego, en el archivo en cuestión, haré lo siguiente:

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

Notarás que importo la exportación predeterminada de mi componente como humilde camel-case, lo que me permite nombrar el nuevo componente con reconocimiento de ubicación en CamelCase para poder usarlo normalmente. Aparte de la línea de importación adicional y la línea de asignación, el componente se comporta como se esperaba y recibe todos sus accesorios normalmente, con la adición de todos los accesorios de ruta. Por lo tanto, puedo redirigir felizmente desde los métodos del ciclo de vida de los componentes con this.props.history.push (), verificar la ubicación, etc.

¡Espero que esto ayude!

5
Zhiwei Huang 2015-11-30 21:09.

También puede combinar es6 y funciones sin estado para obtener un resultado mucho más limpio:

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
      }
    ]
}
3
holyxiaoxin 2016-12-15 00:04.

Para react router 2.x.

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

y en tus rutas ...

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

asegúrese de que la tercera parámetro es un objeto como: { checked: false }.

1
graham mendick 2016-06-21 00:42.

El problema con React Router es que procesa sus componentes y, por lo tanto, evita que pase accesorios. El enrutador de navegación , por otro lado, le permite renderizar sus propios componentes. Eso significa que no tiene que pasar por ningún obstáculo para pasar los accesorios como el siguiente código y el espectáculo de JsFiddle que lo acompaña .

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
Michael Hobbs 2017-01-03 03:23.

Utilice el componente con o sin enrutador según la respuesta de 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}/>
);

O puedes hacerlo de esta manera:

export const Index = ({foo, route}) => {
  const content = (foo) ? foo : (route) ? route.foo : 'No content found!';
  return <h1>{content}</h1>
};
1
illvart 2019-12-04 22:00.

Utilice la solución como a continuación y esto funciona en v3.2.5.

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

o

<Route path="/foo">
  <Content
    lang="foo"
    meta={{
      description: lang_foo.description
    }}
  />
</Route>
1
saigowthamr 2020-08-29 15:20.

Ya he respondido a esto Reaccionar los accesorios de paso del enrutador para enrutar el componente .

Aquí hay algunas formas en las que puede pasar accesorios a un componente de ruta.

Con react-router v5, podemos crear rutas envolviendo con un componente, de modo que podamos pasar fácilmente accesorios al componente deseado como este.

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

De manera similar, puede usar la propiedad de los niños en v5.

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

Si está usando react-router v4, puede pasarlo usando la función de renderizado.

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

(publicado originalmente en https://reactgo.com/react-router-pass-props/ )

0
min may 2016-08-11 17:35.

para el react-router 2.5.2, la solución es muy fácil:

    //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
François Zaninotto 2016-09-21 05:53.

Usando un componente de ruta personalizado , esto es posible en 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>
);

En cuanto al <MyRoute>código del componente, debería ser algo como:

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;

Para obtener más detalles sobre el enfoque del componente de ruta personalizado, consulte la publicación de mi blog sobre el tema: http://marmelab.com/blog/2016/09/20/custom-react-router-component.html

0
Snivio 2018-12-01 09:19.

esta es probablemente la mejor manera de usar react-router-dom con un controlador de cookies

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

y usa una 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
nik.ss 2019-07-04 14:23.
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;

MORE COOL STUFF

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

¿Caduca el repelente de insectos?

¿Caduca el repelente de insectos?

¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.

Atún como Oh, Hello llega a Netflix

Atún como Oh, Hello llega a Netflix

Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.

Actualice a un Sonicare por tan solo $ 30

Actualice a un Sonicare por tan solo $ 30

¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.

India me está pateando el culo

India me está pateando el culo

Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

¿Merrick Garland le ha fallado a Estados Unidos?

Es más de la mitad de la presidencia de Biden. ¿Qué está esperando Merrick Garland?

¿Merrick Garland le ha fallado a Estados Unidos?

Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.

Language