Navegue mediante programación usando el enrutador de reacción

1431

Con react-routerpuedo usar el Linkelemento para crear enlaces que son manejados de forma nativa por react router.

Veo internamente que llama this.context.transitionTo(...).

Quiero hacer una navegación No desde un enlace, sino desde una selección desplegable (como ejemplo). ¿Cómo puedo hacer esto en código? ¿Qué es this.context?

Vi el Navigationmixin, pero ¿puedo hacer esto sin mixins?

George Mauer
fuente
26
@SergioTapia tenga en cuenta que esta pregunta se extiende entre una versión principal de react-router, una versión principal de React y una versión principal de javascript
George Mauer
55
Aquí hay un enlace al tutorial en los documentos oficiales de react router v4: reacttraining.com/react-router/web/guides/scroll-restoration
chitzui
44
Puede consultar esta respuesta stackoverflow.com/questions/44127739/…
Shubham Khatri el
44
Me alegra que hayas respondido esto, pero estoy triste porque tiene que ser así de complicado. Navegar dentro de una aplicación web debe ser fácil y bien documentado. VueJS lo hace trivial. Cada componente obtiene la instancia del enrutador inyectada automáticamente. Hay una sección claramente definida en sus documentos. router.vuejs.org/guide/essentials/navigation.html Me gusta Reaccionar para muchas cosas, pero a veces es demasiado complicado. </rant>
colefner
77
@GeorgeMauer Tienes razón. De eso no se trata esta comunidad. Se trata de responder preguntas, no de disputas sobre marcos. Gracias por el recordatorio.
colefner

Respuestas:

1437

React Router v5.1.0 con ganchos

Hay un nuevo useHistorygancho en React Router> 5.1.0 si está utilizando React> 16.8.0 y componentes funcionales.

import { useHistory } from "react-router-dom";

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

React Router v4

Con v4 de React Router, hay tres enfoques que puede adoptar para el enrutamiento programático dentro de los componentes.

  1. Use el withRoutercomponente de orden superior.
  2. Usar composición y renderizar un <Route>
  3. Usa el context.

React Router es principalmente un contenedor alrededor de la historybiblioteca. historymaneja la interacción con el navegador window.historypara usted con su navegador y sus historiales de hash. También proporciona un historial de memoria que es útil para entornos que no tienen un historial global. Esto es particularmente útil en el desarrollo de aplicaciones móviles ( react-native) y pruebas unitarias con Node.

Una historyinstancia tiene dos métodos para navegar: pushy replace. Si piensa en el historycomo un conjunto de ubicaciones visitadas, pushagregará una nueva ubicación al conjunto y replacereemplazará la ubicación actual en el conjunto con la nueva. Por lo general, querrá usar el pushmétodo cuando esté navegando.

En versiones anteriores de React router, había que crear su propia historyinstancia, pero en la v4 <BrowserRouter>, <HashRouter>y <MemoryRouter>componentes crearán un navegador, hachís, y las instancias de memoria para usted. React Router hace que las propiedades y métodos de la historyinstancia asociada con su enrutador estén disponibles a través del contexto, debajo del routerobjeto.

1. Use el withRoutercomponente de orden superior

El withRoutercomponente de orden superior inyectará el historyobjeto como accesorio del componente. Esto le permite acceder a los métodos pushy replacesin tener que lidiar con context.

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. Use composición y renderice un <Route>

El <Route>componente no es solo para ubicaciones coincidentes. Puede representar una ruta sin ruta y siempre coincidirá con la ubicación actual . El <Route>componente pasa los mismos accesorios que withRouter, por lo que podrá acceder a los historymétodos a través del historyaccesorio.

import { Route } from 'react-router-dom'

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. Usa el contexto *

Pero probablemente no deberías

La última opción es una que solo debe usar si se siente cómodo trabajando con el modelo de contexto de React (la API de contexto de React es estable a partir de la versión 16).

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

1 y 2 son las opciones más simples de implementar, por lo que para la mayoría de los casos de uso, son sus mejores apuestas.

Paul S
fuente
24
Traté de usar el método 1 de esta manera conRouter (({history}) => {console.log ("hhhhhhhh"); history.push ('/ bets')}); Pero nunca funcionó con el enrutador 4
Dmitry Malugin
57
¿¡QUÉ!? ¿Puedo usar en withRouterlugar de pasar historypor todos mis componentes? Gahh necesito pasar más tiempo leyendo documentos ...
hellojeffhall
18
¿Cómo se puede ejecutar history.push('/new-location')sin asociar ese comportamiento a un botón u otro elemento DOM?
Neil
44
error de lanzamiento comoUnexpected use of 'history' no-restricted-globals
Pardeep Jain
18
contextya no es experimental a partir de reaccionar 16.
trysis
921

Respuesta de React-Router 5.1.0+ (usando ganchos y React> 16.8)

Puede usar el nuevo useHistoryenlace en Componentes funcionales y navegar mediante programación:

import { useHistory } from "react-router-dom";

function HomeButton() {
  let history = useHistory();
  // use history.push('/some/path') here
};

Respuesta de React-Router 4.0.0+

En 4.0 y versiones posteriores, use el historial como accesorio de su componente.

class Example extends React.Component {
   // use `this.props.history.push('/some/path')` here
};

NOTA: this.props.history no existe en el caso de que su componente no haya sido procesado por <Route>. Deberías usar <Route path="..." component={YourComponent}/>this.props.history en YourComponent

Respuesta de React-Router 3.0.0+

En 3.0 y superior, use el enrutador como accesorio de su componente.

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

React-Router 2.4.0+ Respuesta

En 2.4 y superiores, use un componente de orden superior para obtener el enrutador como accesorio de su componente.

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes
Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

Respuesta de React-Router 2.0.0+

Esta versión es compatible con versiones anteriores de 1.x, por lo que no hay necesidad de una Guía de actualización. Solo pasar por los ejemplos debería ser lo suficientemente bueno.

Dicho esto, si desea cambiar al nuevo patrón, hay un módulo de Historia del navegador dentro del enrutador al que puede acceder con

import { browserHistory } from 'react-router'

Ahora tiene acceso al historial de su navegador, por lo que puede hacer cosas como empujar, reemplazar, etc.

browserHistory.push('/some/path')

Lecturas adicionales: historias y navegación


React-Router 1.xx Respuesta

No entraré en detalles de actualización. Puedes leer sobre eso en el Guía de actualización

El cambio principal sobre la pregunta aquí es el cambio de Navigation mixin a History. Ahora está usando el historial del navegador API para cambiar la ruta, así que usaremospushState() de ahora en adelante.

Aquí hay un ejemplo usando Mixin:

var Example = React.createClass({
  mixins: [ History ],
  navigateToHelpPage () {
    this.history.pushState(null, `/help`);
  }
})

Tenga en cuenta que esto Historyproviene de rackt / history proyecto . No del propio React-Router.

Si no desea usar Mixin por alguna razón (tal vez debido a la clase ES6), puede acceder al historial que obtiene del enrutador this.props.history. Solo será accesible para los componentes representados por su enrutador. Entonces, si desea usarlo en cualquier componente secundario, debe pasarlo como un atributo a través deprops .

Puede leer más sobre el nuevo lanzamiento en su documentación 1.0.x

Aquí está una página de ayuda específicamente sobre cómo navegar fuera de su componente

Recomienda tomar una referencia history = createHistory()y recurrir replaceStatea eso.

React-Router 0.13.x Respuesta

Me metí en el mismo problema y solo pude encontrar la solución con la combinación de navegación que viene con react-router.

Así es como lo hice

import React from 'react';
import {Navigation} from 'react-router';

let Authentication = React.createClass({
  mixins: [Navigation],

  handleClick(e) {
    e.preventDefault();

    this.transitionTo('/');
  },

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

Pude llamar transitionTo() sin necesidad de acceder.context

O podrías probar el elegante ES6 class

import React from 'react';

export default class Authentication extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();

    this.context.router.transitionTo('/');
  }

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
}

Authentication.contextTypes = {
  router: React.PropTypes.func.isRequired
};

React-Router-Redux

Nota: si está utilizando Redux, hay otro proyecto llamado ReactRouter-Redux que le da Redux fijaciones para ReactRouter, usando un poco el mismo enfoque que Reaccionar-Redux hace

React-Router-Redux tiene algunos métodos disponibles que permiten una navegación sencilla desde los creadores de acciones internas. Estos pueden ser particularmente útiles para las personas que tienen una arquitectura existente en React Native y desean utilizar los mismos patrones en React Web con una sobrecarga mínima.

Explore los siguientes métodos:

  • push(location)
  • replace(location)
  • go(number)
  • goBack()
  • goForward()

Aquí hay un ejemplo de uso, con Redux-Thunk :

./actioncreators.js

import { goBack } from 'react-router-redux'

export const onBackPress = () => (dispatch) => dispatch(goBack())

./viewcomponent.js

<button
  disabled={submitting}
  className="cancel_button"
  onClick={(e) => {
    e.preventDefault()
    this.props.onBackPress()
  }}
>
  CANCEL
</button>
Felipe Skinner
fuente
3
Estoy usando v2.4.0pero el enfoque mencionado no funciona para mí, mi aplicación no se procesa en absoluto y las salidas de la consola: Uncaught TypeError: (0 , _reactRouter.withRouter) is not a functionaquí está el enlace a mi publicación SO: stackoverflow.com/questions/37306166/…
nburk
77
Esta debería ser la respuesta aceptada, la aceptada es un poco desordenada y es muy antigua. @GiantElk Lo tengo funcionando como se describe en la respuesta para la versión 2.6.0.
JMac
2
¿Este enfoque sigue siendo la forma recomendada para la versión 3.0.x? Muchas personas parecen usar el contextcamino.
velocidad
66
en 4.0, this.props.history no existe. Que esta pasando?
Nicolas S.Xu
44
@ NicolasS.Xu this.props.historyno existe en el caso de que su componente no haya sido procesado por <Route>. Debe utilizar <Route path="..." component={YourComponent}/>para tener this.props.historyen YourComponent.
vogdb
508

React-Router v2

Para la versión más reciente ( v2.0.0-rc5), el método de navegación recomendado es presionar directamente sobre el singleton de historial. Puede ver eso en acción en el documento Navegación fuera de Componentes .

Extracto relevante:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

Si usa la API de enrutador reactivo más nueva, debe usar la historydesde this.propsadentro de los componentes para:

this.props.history.push('/some/path');

También ofrece pushStatepero eso está en desuso por advertencias registradas.

Si lo usa react-router-redux, ofrece una pushfunción que puede enviar de la siguiente manera:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

Sin embargo, esto solo se puede usar para cambiar la URL, no para navegar realmente a la página.

Poli
fuente
15
No olvide que la API más nueva no usa, import { browserHistory } from './react-router'sino que crea el historial usando import createBrowserHistory from 'history/lib/createBrowserHistory'. Más adelante, puede acceder historydesde los accesorios de los componentes:this.props.history('/some/path')
Ricardo Pedroni
77
var browserHistory = require('react-router').browserHistory; browserHistory.goBack();
Bobby
77
react-router-redux pushsolo cambia la URL, en realidad no cambia la página. Para hacer las dos cosas, la importación browserHistoryde react-routeruso browserHistory.push('/my-cool-path'). Desafortunadamente, esto no es muy fácil de encontrar. github.com/reactjs/react-router/blob/master/docs/guides/…
Andrew Samuelsen
44
Estoy usando this.props.history.push ('/') pero solo se cambia la URL ... No hay enrutamiento real aquí. ¿Qué me estoy perdiendo?
rgcalsaverini
2
Acabo de subir mi opinión sobre cómo navegar programáticamente en la última react-routerv4
spik3s
56

Así es como se hace esto react-router v2.0.0con ES6 . react-routerse ha alejado de los mixins.

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      <button onClick={this.navigateToPage}>Go!</button>
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}
Alex Miller
fuente
55
Creo que la recomendación actual es usar el historysingleton según lo indicado por @Bobby. Usted podría utilizar context.router, pero lo estás haciendo muy difícil de probar la unidad dichos componentes como una instancia de solo ese componente no tendrá esto en el contexto.
George Mauer
2
@GeorgeMauer Creo que depende de dónde se esté ejecutando el código. Según react docs, se recomienda el uso de context.router si se ejecuta en el servidor. github.com/reactjs/react-router/blob/master/upgrade-guides/…
KumarM
50

React-Router 4.x Respuesta:

Por mi parte, me gusta tener un único objeto de historial que pueda transportar incluso componentes externos. Lo que me gusta hacer es tener un solo archivo history.js que importe bajo demanda y simplemente manipularlo.

Solo tiene que cambiar BrowserRoutera Enrutador y especificar el accesorio de historial. Esto no cambia nada para ti, excepto que tienes tu propio objeto de historial que puedes manipular como quieras.

Necesita instalar el historial , la biblioteca utilizada por react-router.

Ejemplo de uso, notación ES6:

history.js

import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()

BasicComponent.js

import React, { Component } from 'react';
import history from './history';

class BasicComponent extends Component {

    goToIndex(e){
        e.preventDefault();
        history.push('/');
    }

    render(){
        return <a href="#" onClick={this.goToIndex}>Previous</a>;
    }
}

EDITAR 16 de abril de 2018:

Si tiene que navegar desde un componente que realmente se representa desde un Routecomponente, también puede acceder al historial desde accesorios, de la siguiente manera:

BasicComponent.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return <a href="#" onClick={this.navigate}>Previous</a>;
    }
}
Eric Martin
fuente
2
Excepto que los documentos de React Router nos dicen que no deberías, en la mayoría de los casos, usar en Routerlugar de BrowserRouter. BrowserRoutercrea y mantiene el historyobjeto por ti. No debe crear de manera predeterminada la suya propia, solo si ["necesita una integración profunda con herramientas de administración de estado como Redux"]. Reacttraining.com/react-router/web/api/Router
bobbyz
2
Eso es algo que he aprendido con el tiempo y la experiencia. Si bien generalmente es una buena práctica usar el valor predeterminado this.props.history, todavía no he encontrado una solución que pueda ayudarme a hacer algo así en una clase que no sea un componente o cualquier otra herramienta que no esté construida como un componente React para el cual puedes pasar accesorios. Gracias por sus comentarios :)
Eric Martin
44

Para este, quién no controla el lado del servidor y debido a esto está usando el enrutador hash v2:

Coloque su historial en un archivo separado (por ejemplo, app_history.js ES6):

import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });

export default appHistory;

¡Y úsalo en todas partes!

Su punto de entrada para react-router (app.js ES6):

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
  <Router history={appHistory}>
  ...
  </Router>
), document.querySelector('[data-role="app"]'));

Su navegación dentro de cualquier componente (ES6):

import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
  if (err) {
    console.error(err); // login failed
  } else {
    // logged in
    appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
  }
})
Alexey Volodko
fuente
1
Gracias. Tal vez me estoy perdiendo algo. ¿No es esto exactamente lo mismo que las dos respuestas principales?
George Mauer
2
Cuando usa la navegación "hash", en "react-router" v2 necesita instalar un "historial" adicional del módulo (si desea evitar consultas hash extrañas), y en lugar de usar browserHistory necesita usar useRouterHistory (createHashHistory) ( {queryKey: false}). Esta es la razón principal por la que publiqué esto. Mostré cómo navegar con el historial de hash.
Alexey Volodko
1
Oh, ya veo, tienes razón. Ya no estoy en ese proyecto, pero creo que la forma preferida es usar historycualquiera de los dos enfoques ahora
George Mauer
44
¿Por qué esta respuesta no es la mejor? ¿Por qué meterse en tantos problemas con los prototipos de contexto o HOC o de eventos? ¿Por qué no solo importar el historial y usarlo en cualquier lugar que nos plazca? solo tratando de entender la compensación
storm_buster
@storm_buster no hay compensación. ¡Tenemos módulos ES6 y deberíamos usarlos! Este es un escaparate tan típico del uso de su herramienta (reaccione en este caso) para todo, incluso para cosas para las que realmente no desea usarlas.
Capaj
40

React Router V4

tl: dr;

if (navigate) {
  return <Redirect to="/" push={true} />
}

La respuesta simple y declarativa es que debe usar <Redirect to={URL} push={boolean} />en combinación consetState()

push: boolean: cuando es verdadero, la redirección empujará una nueva entrada al historial en lugar de reemplazar la actual.


import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

Ejemplo completo aquí . Lee más aquí .

PD. El ejemplo utiliza los inicializadores de propiedades ES7 + para inicializar el estado. Mira aquí también, si estás interesado.

Lyubomir
fuente
Esta es la mejor respuesta que encontré. El uso withRouterno funcionó cuando ya estaba en la ruta que se está volviendo a cargar. En nuestro caso, teníamos que hacer selectivamente setState(causar return <Redirect>) si ya estábamos en la ruta o history.push()desde otro lugar.
karmakaze
Muy, muy listo. Y sin embargo, muy simple. Tks Lo usé dentro de ReactRouterTable ya que quería manejar el clic en toda la línea. Se usa en onRowClick para establecer el estado. setState ({navigationTo: "/ path /" + row.uuid});
Lovato
Esta es una respuesta a prueba de balas.
Nitin Jadhav
31

Advertencia: esta respuesta solo cubre las versiones ReactRouter anteriores a la 1.0

¡Actualizaré esta respuesta con los casos de uso 1.0.0-rc1 después!

Puedes hacer esto sin mixins también.

let Authentication = React.createClass({
  contextTypes: {
    router: React.PropTypes.func
  },
  handleClick(e) {
    e.preventDefault();
    this.context.router.transitionTo('/');
  },
  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

El problema con los contextos es que no es accesible a menos que defina contextTypesen la clase.

En cuanto al contexto, es un objeto, como accesorios, que se transmiten de padres a hijos, pero se transmiten implícitamente, sin tener que volver a declarar los accesorios cada vez. Ver https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html

Qiming
fuente
26

¡Intenté al menos 10 formas de hacerlo antes de que algo funcionara bien!

La withRouterrespuesta de @Felipe Skinner fue un poco abrumadora para mí, y no estaba segura de querer crear nuevos nombres de clase "ExportedWithRouter".

Aquí está la forma más simple y limpia de hacerlo, alrededor del actual React-Router 3.0.0 y ES6:

React-Router 3.xx con ES6:

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
export default withRouter(Example);

o, si no es tu clase predeterminada, exporta como:

withRouter(Example);
export { Example };

Tenga en cuenta que en 3.xx, el <Link>componente en sí está usando router.push, por lo que puede pasarle cualquier cosa que le pase a la <Link to=etiqueta, como:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'
Ben Wheeler
fuente
1
Funciona totalmente bien Pero responde en 200 OKlugar de 30xcódigo. ¿Cómo puedo solucionar este problema?
Muhammad Ateeq Azam
1
No estoy seguro. Esto nunca se me ocurrió porque no es una solicitud externa, es solo su navegador que usa el propio código de la página para cambiar lo que está en la página. Siempre puede hacer una redirección manual de JavaScript si lo prefiere.
Ben Wheeler
1
también se puede usar con @withRouter como decorador de clase ... va muy bien con mobx
Dan
21

Para hacer la navegación mediante programación, es necesario impulsar una nueva historia a la props.history en su component, así que algo como esto puede hacer el trabajo por usted:

//using ES6
import React from 'react';

class App extends React.Component {

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(e) {
    e.preventDefault()
    /* Look at here, you can add it here */
    this.props.history.push('/redirected');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Redirect!!!
        </button>
      </div>
    )
  }
}

export default App;
Alireza
fuente
Por favor, escriba la versión de react-router
Ash
19

Para los componentes ES6 + React, la siguiente solución funcionó para mí.

Seguí a Felippe Skinner, pero agregué una solución integral para ayudar a los principiantes como yo.

A continuación se muestran las versiones que utilicé:

"react-router": "^ 2.7.0"

"reaccionar": "^ 15.3.1"

A continuación se muestra mi componente de reacción donde utilicé la navegación programática usando react-router:

import React from 'react';

class loginComp extends React.Component {
   constructor( context) {
    super(context);
    this.state = {
      uname: '',
      pwd: ''
    };
  }

  redirectToMainPage(){
        this.context.router.replace('/home');
  }

  render(){
    return <div>
           // skipping html code 
             <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
    </div>;
  }
};

 loginComp.contextTypes = {
    router: React.PropTypes.object.isRequired
 }

 module.exports = loginComp;

A continuación se muestra la configuración de mi enrutador:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(<Router history={browserHistory}>
          <Route path='/' component={ParentComp}>
            <IndexRedirect to = "/login"/>
            <Route path='/login' component={LoginComp}/>
            <Route path='/home' component={HomeComp}/>
            <Route path='/repair' component={RepairJobComp} />
            <Route path='/service' component={ServiceJobComp} />
          </Route>
        </Router>, document.getElementById('root'));
Softwareddy
fuente
19

Puede que no sea el mejor enfoque, pero ... Usando react-router v4, el siguiente mecanografiado podría dar una idea para algunos.

En el componente representado a continuación, por ejemplo LoginPage, routerse puede acceder al objeto y solo debe llamar router.transitionTo('/homepage')para navegar.

El código de navegación fue tomado de .

"react-router": "^4.0.0-2", "react": "^15.3.1",

import Router from 'react-router/BrowserRouter';
import { History } from 'react-history/BrowserHistory';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();

interface MatchWithPropsInterface {
  component: typeof React.Component,
  router: Router,
  history: History,
  exactly?: any,
  pattern: string
}

class MatchWithProps extends React.Component<MatchWithPropsInterface,any> {
  render() {
    return(
      <Match {...this.props} render={(matchProps) => (
             React.createElement(this.props.component, this.props)

        )}
       />
    )
  }
}

ReactDOM.render(
    <Router>
      {({ router }) => (
        <div>
          <MatchWithProps exactly pattern="/" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/login" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/homepage" component={HomePage} router={router} history={history} />
          <Miss component={NotFoundView} />
        </div>
      )}
    </Router>,

   document.getElementById('app')
);

mcku
fuente
1
¿Por qué no lo usas con Router y browserHistory?
Erwin Mayer
1
@Erwin La API es diferente en v4. Vea este github.com/ReactTraining/react-router/issues/3847 .
mcku
1
@mcku ¿De dónde sacaste tu archivo dts mecanografiado para react-router v4?
jmathew
1
@jmathew No tengo ninguna definición de tipo para react-router v4
mcku
16

En React-Router v4 y ES6

Puedes usar withRoutery this.props.history.push.

import {withRouter} from 'react-router-dom';

class Home extends Component {

    componentDidMount() {
        this.props.history.push('/redirect-to');
    }
}

export default withRouter(Home);
Hossein
fuente
2
Ya mencionado en varias otras respuestas (incluso en la respuesta superior)
George Mauer
13

Para usar withRoutercon un componente basado en clases, intente algo como esto a continuación. No olvide cambiar la declaración de exportación para usar withRouter:

import { withRouter } from 'react-router-dom'

class YourClass extends React.Component {
  yourFunction = () => {
    doSomeAsyncAction(() =>
      this.props.history.push('/other_location')
    )
  }

  render() {
    return (
      <div>
        <Form onSubmit={ this.yourFunction } />
      </div>
    )
  }
}

export default withRouter(YourClass);
Janos
fuente
11

basado en la respuesta anterior
de José Antonio Postigo y Ben Wheeler
la novedad? debe escribirse en mecanografiado
y el uso de decoradores
O propiedad / campo estático

import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";

export interface INavigatorProps {
    router?: ReactRouter.History.History;
}

/**
 * Note: goes great with mobx 
 * @inject("something") @withRouter @observer
 */
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
    navigate: (to: string) => void;
    constructor(props: INavigatorProps) {
        super(props);
        let self = this;
        this.navigate = (to) => self.props.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

/**
 * Non decorated 
 */
export class Navigator2 extends Component<INavigatorProps, {}> {

    static contextTypes = {
        router: React.PropTypes.object.isRequired,
    };

    navigate: (to: string) => void;
    constructor(props: INavigatorProps, context: any) {
        super(props, context);
        let s = this;
        this.navigate = (to) =>
            s.context.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

con cualquier npm instalado hoy. "react-router": "^ 3.0.0" y
"@ types / react-router": "^ 2.0.41"

Dan
fuente
11

Con React-Router v4 en el horizonte, ahora hay una nueva forma de hacerlo.

import { MemoryRouter, BrowserRouter } from 'react-router';

const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;

<Router location="/page-to-go-to"/>

react-lego es una aplicación de ejemplo que muestra cómo usar / actualizar react-router e incluye ejemplos de pruebas funcionales que navegan por la aplicación.

Peter.mouland
fuente
55
Esto es genial para navegar desde la función de renderizado, aunque me pregunto cómo navegar desde algo como un gancho de ciclo de vida o redux.
Ruben Martinez Jr.
11

En reaccionar router v4. Sigo este camino de dos vías mediante programación.

1. this.props.history.push("/something/something")
2. this.props.history.replace("/something/something")

Número dos

Reemplaza la entrada actual en la pila de historial

Para obtener el historial de accesorios, es posible que deba envolver su componente con

withRouter

saiful619945
fuente
¡¡Gracias!! La mejor respuesta
Taha Farooqui
9

Si está utilizando hash o historial del navegador, puede hacerlo

hashHistory.push('/login');
browserHistory.push('/login');
Zaman Afzal
fuente
2
hashHistory.push, no puede leer la propiedad "push" de undefined. ¿De dónde importan estos?
ArchNoob
importar {hashHistory} desde "react-router"; puedes importarlo de esta manera en la parte superior.
Zaman Afzal
Estoy usando su muestra de código de mi archivo redux saga, importando tal como lo dijo y lo uso, pero sigo obteniendo ese TypeError.
ArchNoob
8

Con la versión actual de React (15.3), this.props.history.push('/location');funcionó para mí, pero mostró la siguiente advertencia:

browser.js: 49 Advertencia: [react-router] props.historyy context.historyestán en desuso. Por favor use context.router.

y lo resolví usando context.routerasí:

import React from 'react';

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.backPressed = this.backPressed.bind(this);
    }

    backPressed() {
        this.context.router.push('/back-location');
    }

    ...
}

MyComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
};

export default MyComponent;
José Antonio Postigo
fuente
1
Esto está funcionando para V4. Bueno ... cerca ... necesita ser this.context.router.history.push ('/ back-location');
velohomme
7

React-Router V4

si está utilizando la versión 4, entonces puede usar mi biblioteca (Shameless plug) donde simplemente envía una acción y ¡todo funciona!

dispatch(navigateTo("/aboutUs"));

trippler

Garry Taylor
fuente
5

Aquellos que enfrentan problemas para implementar esto en react-router v4.

Aquí hay una solución de trabajo para navegar a través de la aplicación react desde acciones redux.

history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

App.js / Route.jsx

import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
 <Route path="/test" component={Test}/>
</Router>

otro_archivo.js O archivo redux

import history from './history' 

history.push('/test') // this should change the url and re-render Test component

Todo gracias a este comentario: comentario de problemas de ReactTraining

gravedad refleja
fuente
4

Si empareja RR4 w / redux a través de react-router-redux , use también la react-router-reduxopción de creadores de acciones de enrutamiento .

import { push, replace, ... } from 'react-router-redux'

class WrappedComponent extends React.Component {
  handleRedirect(url, replaceState = true) { 
    replaceState 
      ? this.props.dispatch(replace(url)) 
      : this.props.dispatch(push(url)) 
  }
  render() { ... }
}

export default connect(null)(WrappedComponent)

Si usa redux thunk / saga para administrar el flujo asíncrono, importe los creadores de acciones anteriores en acciones redux y enganche para reaccionar componentes usando mapDispatchToProps podría ser mejor.

Xlee
fuente
1
react-router-reduxha quedado en desuso / archivado por un largo tiempo
oligofren
4

También puede usar el useHistorygancho en un componente sin estado. Ejemplo de los documentos.

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

  return (
    <button type="button" onClick={() => history.push("/home")}>
      Go home
    </button>
  )
}

Nota: Se agregaron ganchos [email protected]y requierenreact@>=16.8

Nickofthyme
fuente
1
Buena llamada, ¿podría notar a qué versión de react-router y reaccionar se refiere? Este es un nuevo cambio que no siempre estuvo disponible
George Mauer,
3

La respuesta correcta fue para mí al momento de escribir

this.context.router.history.push('/');

Pero necesita agregar PropTypes a su componente

Header.contextTypes = {
  router: PropTypes.object.isRequired
}
export default Header;

No olvides importar PropTypes

import PropTypes from 'prop-types';
administrador de página web
fuente
Escriba la versión de react-router y qué importó de react-router
Ash
No hay nada que importar y esta es la versión "react-router": "^ 4.2.0"
webmaster
3

Quizás no sea la mejor solución, pero hace el trabajo:

import { Link } from 'react-router-dom';

// create functional component Post
export default Post = () => (
    <div className="component post">

        <button className="button delete-post" onClick={() => {
            // ... delete post
            // then redirect, without page reload, by triggering a hidden Link
            document.querySelector('.trigger.go-home').click();
        }}>Delete Post</button>

        <Link to="/" className="trigger go-home hidden"></Link>

    </div>
);

Básicamente, una lógica vinculada a una acción (en este caso, una eliminación posterior) terminará llamando a un disparador para redireccionar. Esto no es ideal porque agregará un 'disparador' del nodo DOM a su marcado solo para que pueda llamarlo convenientemente cuando sea necesario. Además, interactuará directamente con el DOM, que en un componente React puede no ser deseado.

Aún así, este tipo de redireccionamiento no se requiere con tanta frecuencia. Por lo tanto, uno o dos enlaces ocultos adicionales en el marcado de su componente no afectarían tanto, especialmente si les da nombres significativos.

neatsu
fuente
¿Puede explicar por qué alguna vez usaría esto sobre la solución aceptada?
George Mauer
Es solo una solución alternativa al problema discutido. Como ya se dijo, no es ideal, pero funciona bien para redireccionamientos programáticos.
neatsu
2

Esto funcionó para mí, no se necesitan importaciones especiales:

<input 
  type="button" 
  name="back" 
  id="back" 
  class="btn btn-primary" 
  value="Back" 
  onClick={() => { this.props.history.goBack() }} 
/>
JJ_Coder4Hire
fuente
Por supuesto, esto necesita importaciones especiales: su componente no se ha historyagregado propssolo. Eso proviene de un HoC que necesitarías importar para usar (los componentes enviados directamente por Routeson envueltos automáticamente por ese HoC pero luego necesitas una importación para Route...)
George Mauer
2

use hookrouter en su lugar, la alternativa moderna al router de reacción

https://www.npmjs.com/package/hookrouter

import { useRoutes, usePath, A} from "hookrouter";

para responder la pregunta de OP sobre el enlace a través del cuadro de selección, puede hacerlo:

navigate('/about');
StefanBob
fuente
FYI. El propio autor llama a esta biblioteca "una prueba de concepto" y no ha tenido actividad durante casi un año (junio de 2019).
MEMark
@MEMark eso es porque ya es perfecto
StefanBob
Bueno, los 38 problemas abiertos, junto con el hecho de que la versión 2.0 será una reescritura completa según el autor, dice lo contrario.
MEMark
1

Para React Router v4 +

Suponiendo que no necesitará navegar durante el renderizado inicial (para el cual puede usar el <Redirect>componente), esto es lo que estamos haciendo en nuestra aplicación.

Defina una ruta vacía que devuelva nulo, esto le permitirá obtener acceso al objeto de historial. Debe hacer esto en el nivel superior donde suRouter se define su.

Ahora usted puede hacer todas las cosas que se pueden hacer en la historia como history.push(), history.replace(), history.go(-1)etc!

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';

let routeHistory = null;

export function navigateTo(path) {
  if(routeHistory !== null) {
    routeHistory.push(path);
  }
}

export default function App(props) {
  return (
    <HashRouter hashType="noslash">
      <Route
        render={({ history }) => {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    </HashRouter>
  );
}
Aftab Khan
fuente
1

react-router-dom: 5.1.2

  • Este sitio tiene 3 páginas, todas las cuales se representan dinámicamente en el navegador.

  • Aunque la página nunca se actualiza, observe cómo React Router mantiene la URL actualizada mientras navega por el sitio. Esto conserva el historial del navegador, asegurando que cosas como el botón de retroceso y los marcadores funcionen correctamente

  • Un conmutador examina todos sus elementos secundarios y muestra el primero cuya ruta coincide con la URL actual. Use una en cualquier momento que tenga varias rutas, pero solo desea que una de ellas se procese a la vez

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";



export default function BasicExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        </ul>

        <hr />

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

// You can think of these components as "pages"
// in your app.

function Home() {
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

function About() {
  return (
    <div>
      <h2>About</h2>
    </div>
  );
}

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
    </div>
  );
}```
GOVINDARAJ
fuente
Bienvenido a SO! Cuando responda a una pregunta con tantas respuestas, intente mostrar los beneficios de la suya.
David García Bodego
Esto tampoco responde a la pregunta que es cómo hacerlo programáticamente desde js imperativo, no con marcado.
George Mauer
1

Entonces, en mi respuesta, hay 3 formas diferentes de redirigir programáticamente a una ruta. Algunas de las soluciones ya se han presentado, pero las siguientes se centraron solo en componentes funcionales. con una aplicación de demostración adicional.

Usando las siguientes versiones:

reaccionar: 16.13.1

react-dom: 16.13.1

enrutador de reacción: 5.2.0

react-router-dom: 5.2.0

mecanografiado: 3.7.2

Configuración:

Entonces, en primer lugar, está utilizando la solución HashRouter, configurada de la siguiente manera:

<HashRouter>
    // ... buttons for redirect

    <Switch>
      <Route exact path="/(|home)" children={Home} />
      <Route exact path="/usehistory" children={UseHistoryResult} />
      <Route exact path="/withrouter" children={WithRouterResult} />
      <Route exact path="/redirectpush" children={RedirectPushResult} />
      <Route children={Home} />
    </Switch>
</HashRouter>

De la documentación sobre <HashRouter>:

A <Router>que usa la parte hash de la URL (es decir window.location.hash) para mantener su UI sincronizada con la URL.

Soluciones:

  1. Usando <Redirect>para empujar usando useState:

Usando en un componente funcional ( RedirectPushActioncomponente de mi repositorio) podemos usar useStatepara manejar la redirección. La parte difícil es que una vez que se produjo la redirección, debemos volver a establecer el redirectestado false. Al usar setTimeOutcon 0retraso estamos esperando hasta que React se comprometaRedirect con el DOM y luego recuperemos el botón para usarlo la próxima vez.

Por favor encuentre mi ejemplo a continuación:

const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
    let render = null;
    if (redirect) {
        render = <Redirect to="/redirectpush" push={true} />

        // in order wait until commiting to the DOM
        // and get back the button for clicking next time
        setTimeout(() => setRedirect(false), 0);
    }
    return render;
}, [redirect]);

return <>
    {handleRedirect()}
    <button onClick={() => setRedirect(true)}>
        Redirect push
    </button>
</>

De la <Redirect>documentación:

La representación de a <Redirect>navegará a una nueva ubicación. La nueva ubicación anulará la ubicación actual en la pila del historial, como lo hacen las redirecciones del lado del servidor (HTTP 3xx).

  1. Usando useHistorygancho:

En mi solución hay un componente llamado UseHistoryActionque representa lo siguiente:

let history = useHistory();

return <button onClick={() => { history.push('/usehistory') }}>
    useHistory redirect
</button>

El useHistorygancho nos da acceso al objeto de historial que nos ayuda a navegar programáticamente o cambiar rutas.

  1. Usando withRouter, obtenga el historyde props:

Creado un componente llamado WithRouterAction, se muestra a continuación:

const WithRouterAction = (props:any) => {
    const { history } = props;

    return <button onClick={() => { history.push('/withrouter') }}>
        withRouter redirect
    </button>
}

export default withRouter(WithRouterAction);

Lectura de la withRouterdocumentación:

Puede obtener acceso a las historypropiedades del objeto y la <Route>coincidencia más cercana a través del withRoutercomponente de orden superior. withRouterpasará actualizado match, locationy historyapoyos al componente envuelto siempre que se procese.

Manifestación:

Para una mejor representación, he creado un repositorio de GitHub con estos ejemplos, por favor encuéntrelo a continuación:

https://github.com/norbitrial/react-router-programmatic-redirect-examples

¡Espero que esto ayude!

norbitrial
fuente