react change reactjs react-router

reactjs - change - Navegue mediante programación usando el enrutador de reacción



react change title (29)

Con react-router puedo usar el elemento Link para crear enlaces que sean manejados de forma nativa por react router.

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

Quiero hacer una navegación, pero no desde un enlace, desde una selección desplegable, por ejemplo. ¿Cómo puedo hacer esto en código? ¿Qué es this.context ?

Vi el mixin de Navigation , pero ¿puedo hacer esto sin mixins?


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 con setState()

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 here . Lee más here .

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


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 Router se define su.

Ahora usted puede hacer todas las cosas que se pueden hacer en history 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> ); }


En React-Router v4 y ES6

Puede usar withRouter y 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);


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> . Debe usar <Route path="..." component={YourComponent}/> para tener 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: Histories y Navigation

React-Router 1.xx Respuesta

No entraré en detalles de actualización. Puede leer sobre eso en la 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, por lo que 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 este History proviene del proyecto rackt/history . 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 desde this.props.history . Solo será accesible para los componentes representados por su enrutador. Por lo tanto, si desea usarlo en cualquier componente secundario, debe pasarlo 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 un history = createHistory() referencia history = createHistory() y llamar a replaceState sobre 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 a transitionTo() sin necesidad de acceder a .context

O podrías probar la elegante class ES6

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 React-Router-Redux que le ofrece enlaces redux para ReactRouter, utilizando el mismo enfoque que React-Redux

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>


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 contextTypes en 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


React Router v4

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

  1. Utilice el componente de orden superior withRouter .
  2. Use composición y renderice una <Route>
  3. Usa el context .

React Router es principalmente un contenedor alrededor de la biblioteca de history . history maneja la interacción con la window.history del navegador. window.history para 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 instancia de history tiene dos métodos para navegar: push y replace . Si piensa en el history como una matriz de ubicaciones visitadas, push agregará una nueva ubicación a la matriz y replace reemplazará la ubicación actual en la matriz con la nueva. Por lo general, querrá usar el método push cuando esté navegando.

En versiones anteriores de React Router, tenía que crear su propia instancia de history , pero en v4 los <BrowserRouter> , <HashRouter> y <MemoryRouter> crearán un navegador, hash y instancias de memoria para usted. React Router hace que las propiedades y métodos de la instancia de history asociados con su enrutador estén disponibles a través del contexto, bajo el objeto router .

1. Use el componente de orden superior withRouter

El componente de orden superior withRouter inyectará el objeto de history como accesorio del componente. Esto le permite acceder a los métodos de push y replace sin tener que lidiar con el 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 la composición y renderice una <Route>

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

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 context de React. Aunque el contexto es una opción, debe enfatizarse que el contexto es una API inestable y React tiene una sección Por qué no usar el contexto en su documentación. ¡Así que úselo bajo su propio riesgo!

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.


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 BrowserRouter a Router y especificar el accesorio de historial. Esto no cambia nada para usted, excepto que tiene su propio objeto de historial que puede manipular como desee.

Necesita instalar el history , 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 procesa desde un componente de Route , 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>; } }


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 la navegación fuera del documento Componentes .

Extracto relevante:

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

Si usa la API de enrutador reactivo más nueva, debe hacer uso del history de this.props cuando está dentro de los componentes, por lo que:

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

También ofrece pushState pero está en desuso por advertencias registradas.

Si usa react-router-redux , ofrece una función push 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.


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 reaccionar desde acciones redux.

history.js

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

App.js / Route.jsx

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

otro_archivo.js O archivo redux

dispatch(navigateTo("/aboutUs"));

Todo gracias a este comentario: comentario de problemas de ReactTraining


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

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


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


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.


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!

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

trippler


Si empareja RR4 w / redux a través de react-router-redux , use también la react-router-redux opció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.


Simplemente use this.props.history.push(''/where/to/go'');


También puede usar el useHistory gancho 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 requieren react@>=16.8


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

La respuesta withRouter @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 componente <Link> sí está usando router.push , por lo que puede pasarle cualquier cosa que le pase a la etiqueta <Link to= , como:

this.props.router.push({pathname: ''/some/path'', query: {key1: ''val1'', key2: ''val2''})''


Así es como se hace esto con react-router v2.0.0 con ES6 . react-router 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 }


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.


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.history y context.history están en desuso. Por favor use context.router .

y lo resolví usando context.router así:

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;


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


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

Coloque su history 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() } })


Para hacer la navegación mediante programación, debe insertar una nueva historia en los accesorios.historia en su component , por lo 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;


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


Para usar withRouter con un componente basado en clases, intente algo como esto a continuación. No olvide cambiar la declaración de exportación para usar con 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);


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 , se puede acceder al objeto router y simplemente llame a router.transitionTo(''/homepage'') para navegar.

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

"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'') );


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

hashHistory.push(''/login''); browserHistory.push(''/login'');


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"


Enrutamiento de reacción simple:

Enlace a mi código sandbox. Tiene algunos otros programas simples react-redux.