¿Cómo navegar mediante programación usando React Router?

Resuelto George Mauer asked hace 9 años • 50 respuestas

Con react-routerpuedo usar el Linkelemento para crear enlaces que son manejados de forma nativa por el enrutador de reacción.

Veo que internamente 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 avatar Jun 27 '15 00:06 George Mauer
Aceptado

ACTUALIZACIÓN: 2022: React Router v6.6.1 con useNavigate

El useHistory()gancho ahora está en desuso. Si está utilizando React Router 6, la forma correcta de navegar mediante programación es la siguiente:

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

function HomeButton() {
  const navigate = useNavigate();

  function handleClick() {
    navigate("/home");
  }

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

React Router v5.1.0 con ganchos

Hay un nuevo useHistoryenlace 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>
  );
}

Reaccionar enrutador v4

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

  1. Utilice el withRoutercomponente de orden superior.
  2. Usar composición y renderizar<Route>
  3. Utilizar el context.

React Router es principalmente un contenedor de la historybiblioteca. historymaneja la interacción con el navegador window.historypor 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 una matriz de ubicaciones visitadas, pushagregará una nueva ubicación a la matriz y replacereemplazará la ubicación actual en la matriz con la nueva. Normalmente querrás utilizar este pushmétodo cuando estés navegando.

En versiones anteriores de React Router, tenía que crear su propia historyinstancia, pero en la versión 4 <BrowserRouter>, los componentes <HashRouter>, y <MemoryRouter>crearán instancias de navegador, hash y 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. Utilice 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 el archivo 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. Usa composición y renderiza<Route>

El <Route>componente no es sólo para hacer coincidir ubicaciones. Puede representar una ruta sin camino 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 sencillas de implementar, por lo que, para la mayoría de los casos de uso, son las mejores opciones.

Paul S avatar Feb 08 '2017 18:02 Paul S

React-Router v6+ Respuesta

TL;DR: Puedes usar el nuevo useNavigategancho.

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

function Component() {
  let navigate = useNavigate();
  // Somewhere in your code, e.g. inside a handler:
  navigate("/posts"); 
}

El useNavigategancho devuelve una función que se puede utilizar para la navegación programática.

Ejemplo de la documentación del enrutador de reacción

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

function SignupForm() {
  let navigate = useNavigate();

  async function handleSubmit(event) {
    event.preventDefault();
    await submitForm(event.target);
    navigate("../success", { replace: true });
    // replace: true will replace the current entry in 
    // the history stack instead of adding a new one.

  }

  return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}

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

Puede utilizar el 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
};

React-Router 4.0.0+ Respuesta

En 4.0 y superiores, utilice el historial como accesorio de su componente.

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

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

React-Router 3.0.0+ Respuesta

En 3.0 y superiores, utilice 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, utilice 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
};

React-Router 2.0.0+ Respuesta

Esta versión es compatible con versiones anteriores de 1.x, por lo que no es necesaria una guía de actualización. Simplemente repasar los ejemplos debería ser suficiente.

Dicho esto, si deseas cambiar al nuevo patrón, hay un browserHistorymódulo dentro del enrutador al que puedes acceder con

import { browserHistory } from 'react-router'

Ahora tienes acceso al historial de tu navegador, por lo que puedes hacer cosas como insertar, reemplazar, etc... Como:

browserHistory.push('/some/path')

Lectura adicional: Historias y navegación


Respuesta del enrutador React 1.xx

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

El principal cambio sobre la pregunta aquí es el cambio de Navigationmixin a History. Ahora está usando la API del historial del navegador para cambiar la ruta, así que la usaremos pushState()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 del proyecto rackt/history . No del propio React-Router.

Si no desea utilizar Mixin por algún motivo (tal vez debido a la clase ES6), puede acceder al historial que obtiene del enrutador desde this.props.history. Solo será accesible para los componentes renderizados por su Router. Por lo tanto, si desea utilizarlo en algún componente secundario, debe transmitirlo como un atributo a través de props.

Puede leer más sobre la nueva versión en su documentación 1.0.x.

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

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

React-Router 0.13.x Respuesta

Me metí en el mismo problema y solo pude encontrar la solución con el mixin de navegación que viene con reaccionar-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 ES6class

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

Reaccionar-Router-Redux

Note: if you're using Redux, there is another project called React-Router-Redux that gives you redux bindings for ReactRouter, using somewhat the same approach that React-Redux does

React-Router-Redux has a few methods available that allow for simple navigating from inside action creators. These can be particularly useful for people that have existing architecture in React Native, and they wish to utilize the same patterns in React Web with minimal boilerplate overhead.

Explore the following methods:

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

Here is an example usage, with 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 avatar Jun 26 '2015 17:06 Felipe Skinner