react link example exact reactjs redux react-router react-router-v4

reactjs - link - ¿Cómo pasar a la historia en React Router v4?



router example react (19)

Aquí está mi truco (este es mi archivo de nivel raíz, con un poco de redux mezclado allí, aunque no estoy usando react-router-redux ):

const store = configureStore() const customHistory = createBrowserHistory({ basename: config.urlBasename || '''' }) ReactDOM.render( <Provider store={store}> <Router history={customHistory}> <Route component={({history}) => { window.appHistory = history return ( <App /> ) }}/> </Router> </Provider>, document.getElementById(''root'') )

Entonces puedo usar window.appHistory.push() cualquier lugar que desee (por ejemplo, en mi tienda redux funciones / thunks / sagas, etc.) Esperaba poder usar window.customHistory.push() pero por alguna razón react-router nunca pareció actualizarse a pesar de que la URL cambió. Pero de esta manera tengo la instancia EXACT que utiliza el react-router . No me encanta poner cosas en el ámbito global, y esta es una de las pocas cosas con las que haría eso. Pero es mejor que cualquier otra alternativa que haya visto IMO.

En la versión actual de React Router (v3) puedo aceptar una respuesta del servidor y usar browserHistory.push para ir a la página de respuesta adecuada. Sin embargo, esto no está disponible en v4, y no estoy seguro de cuál es la forma adecuada de manejar esto.

En este ejemplo, usando Redux, components / app-product-form.js llama a this.props.addProduct(props) cuando un usuario envía el formulario. Cuando el servidor devuelve un éxito, el usuario es llevado a la página Carrito.

// actions/index.js export function addProduct(props) { return dispatch => axios.post(`${ROOT_URL}/cart`, props, config) .then(response => { dispatch({ type: types.AUTH_USER }); localStorage.setItem(''token'', response.data.token); browserHistory.push(''/cart''); // no longer in React Router V4 }); }

¿Cómo puedo hacer una redirección a la página del carrito desde la función React Router v4?


Así es como lo hice:

import React, {Component} from ''react''; export default class Link extends Component { constructor(props) { super(props); this.onLogout = this.onLogout.bind(this); } onLogout() { this.props.history.push(''/''); } render() { return ( <div> <h1>Your Links</h1> <button onClick={this.onLogout}>Logout</button> </div> ); } }

Utilice this.props.history.push(''/cart''); para redirigir a la página del carrito se guardará en el objeto de historial

Disfruta, Michael.


Cree un Router personalizado con su propio browserHistory :

import React from ''react''; import { Router } from ''react-router-dom''; import { createBrowserHistory } from ''history''; export const history = createBrowserHistory(); const ExtBrowserRouter = ({children}) => ( <Router history={history} > { children } </Router> ); export default ExtBrowserRouter

Luego, en su raíz donde define su Router , use lo siguiente:

import React from ''react''; import { /*BrowserRouter,*/ Route, Switch, Redirect } from ''react-router-dom''; //Use ''ExtBrowserRouter'' instead of ''BrowserRouter'' import ExtBrowserRouter from ''./ExtBrowserRouter''; ... export default class Root extends React.Component { render() { return ( <Provider store={store}> <ExtBrowserRouter> <Switch> ... <Route path="/login" component={Login} /> ... </Switch> </ExtBrowserRouter> </Provider> ) } }

Finalmente, importe el history donde lo necesite y úselo:

import { history } from ''../routers/ExtBrowserRouter''; ... export function logout(){ clearTokens(); history.push(''/login''); //WORKS AS EXPECTED! return Promise.reject(''Refresh token has expired''); }


De acuerdo con la documentación de React Router v4 - sesión de Redux Deep Integration

Se necesita una integración profunda para:

"poder navegar enviando acciones"

Sin embargo, recomiendan este enfoque como una alternativa a la "integración profunda":

"En lugar de enviar acciones para navegar, puede pasar el objeto de historial proporcionado para enrutar componentes a sus acciones y navegar con él allí".

Entonces puede envolver su componente con el componente de orden superior withRouter:

export default withRouter(connect(null, { actionCreatorName })(ReactComponent));

que pasará la API de historial a los accesorios. Entonces puedes llamar al creador de la acción pasando la historia como un parámetro. Por ejemplo, dentro de su ReactComponent:

onClick={() => { this.props.actionCreatorName( this.props.history, otherParams ); }}

Luego, dentro de tus acciones / index.js:

export function actionCreatorName(history, param) { return dispatch => { dispatch({ type: SOME_ACTION, payload: param.data }); history.push("/path"); }; }


En este caso, estás pasando accesorios a tu puño. Entonces puedes simplemente llamar

props.history.push(''/cart'')

Si este no es el caso, aún puede pasar el historial de su componente

export function addProduct(data, history) { return dispatch => { axios.post(''/url'', data).then((response) => { dispatch({ type: types.AUTH_USER }) history.push(''/cart'') }) } }


La manera más simple en React Router 4 es usar

this.props.history.push(''/new/url'');

Pero para usar este método, su componente existente debe tener acceso al objeto de history . Podemos acceder por

  1. Si su componente está vinculado a la Route directamente, entonces su componente ya tiene acceso al objeto de history .

    p.ej:

    <Route path="/profile" component={ViewProfile}/>

    Aquí ViewProfile tiene acceso al history .

  2. Si no está conectado a la Route directamente.

    p.ej:

    <Route path="/users" render={() => <ViewUsers/>}

    Luego tenemos que usar withRouter , una función de orden superior para deformar el componente existente.

    ViewUsers Inside ViewUsers

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

    • export default withRouter(ViewUsers);

    Eso es todo, su componente ViewUsers tiene acceso al objeto de history .

ACTUALIZAR

2 : en este escenario, pase todos los props ruta a su componente, y luego podemos acceder a this.props.history desde el componente incluso sin un HOC

p.ej:

<Route path="/users" render={props => <ViewUsers {...props} />}


Ofrezco una solución más en caso de que valga la pena para otra persona.

Tengo un archivo history.js donde tengo lo siguiente:

import createHistory from ''history/createBrowserHistory'' const history = createHistory() history.pushLater = (...args) => setImmediate(() => history.push(...args)) export default history

Luego, en mi raíz donde defino mi enrutador, uso lo siguiente:

import history from ''../history'' import { Provider } from ''react-redux'' import { Router, Route, Switch } from ''react-router-dom'' export default class Root extends React.Component { render() { return ( <Provider store={store}> <Router history={history}> <Switch> ... </Switch> </Router> </Provider> ) } }

Finalmente, en my actions.js importo Historial y uso pushLater

import history from ''./history'' export const login = createAction( ... history.pushLater({ pathname: PATH_REDIRECT_LOGIN }) ...)

De esta manera, puedo impulsar nuevas acciones después de las llamadas a la API.

¡Espero eso ayude!


Pregunta desagradable, me llevó bastante tiempo, pero finalmente, lo resolví de esta manera:

Envuelva su contenedor withRouter y pase el historial a su acción en la función mapDispatchToProps . En acción, use history.push (''/ url'') para navegar.

Acción:

export function saveData(history, data) { fetch.post(''/save'', data) .then((response) => { ... history.push(''/url''); }) };

Envase:

import { withRouter } from ''react-router-dom''; ... const mapDispatchToProps = (dispatch, ownProps) => { return { save: (data) => dispatch(saveData(ownProps.history, data))} }; export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Container));

Esto es válido para React Router v4.x.


Pude lograr esto usando bind() . Quería hacer clic en un botón en index.jsx , publicar algunos datos en el servidor, evaluar la respuesta y redirigir a success.jsx . Así es como lo resolví ...

index.jsx :

import React, { Component } from "react" import { postData } from "../../scripts/request" class Main extends Component { constructor(props) { super(props) this.handleClick = this.handleClick.bind(this) this.postData = postData.bind(this) } handleClick() { const data = { "first_name": "Test", "last_name": "Guy", "email": "[email protected]" } this.postData("person", data) } render() { return ( <div className="Main"> <button onClick={this.handleClick}>Test Post</button> </div> ) } } export default Main

request.js :

import { post } from "./fetch" export const postData = function(url, data) { // post is a fetch() in another script... post(url, data) .then((result) => { if (result.status === "ok") { this.props.history.push("/success") } }) }

success.jsx :

import React from "react" const Success = () => { return ( <div className="Success"> Hey cool, got it. </div> ) } export default Success

Entonces, al vincular this a postData en index.jsx , pude acceder a this.props.history en request.js ... luego puedo reutilizar esta función en diferentes componentes, solo tengo que asegurarme de recordar haber incluido this.postData = postData.bind(this) en el constructor() .


Puede usar los métodos del history fuera de sus componentes. Intenta de la siguiente manera.

Primero, cree un objeto de history que use el paquete de historial :

// src/history.js import { createBrowserHistory } from ''history''; export default createBrowserHistory();

Luego envuélvala en <Router> ( tenga en cuenta que debe usar import { Router } lugar de import { BrowserRouter as Router } ):

// src/index.jsx // ... import { Router, Route, Link } from ''react-router-dom''; import history from ''./history''; ReactDOM.render( <Provider store={store}> <Router history={history}> <div> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/login">Login</Link></li> </ul> <Route exact path="/" component={HomePage} /> <Route path="/login" component={LoginPage} /> </div> </Router> </Provider>, document.getElementById(''root''), );

Cambie su ubicación actual desde cualquier lugar, por ejemplo:

// src/actions/userActionCreators.js // ... import history from ''../history''; export function login(credentials) { return function (dispatch) { return loginRemotely(credentials) .then((response) => { // ... history.push(''/''); }); }; }

UPD : También puede ver un ejemplo ligeramente diferente en las Preguntas frecuentes de React Router .


React Router v4 es fundamentalmente diferente de v3 (y anterior) y no puede hacer browserHistory.push() como solía hacerlo.

Esta discusión parece relacionada si quieres más información:

  • Crear un nuevo browserHistory no funcionará porque <BrowserRouter> crea su propia instancia de historial y escucha los cambios al respecto. Por lo tanto, una instancia diferente cambiará la URL pero no actualizará el <BrowserRouter> .
  • browserHistory no está expuesto por react-router en v4, solo en v2.

En cambio, tiene algunas opciones para hacer esto:

  • Utilice el withRouter alto orden withRouter

    En su lugar, debe usar el componente de orden superior withRouter al componente que empujará al historial. Por ejemplo:

    import React from "react"; import { withRouter } from "react-router-dom"; class MyComponent extends React.Component { ... myFunction() { this.props.history.push("/some/Path"); } ... } export default withRouter(MyComponent);

    Consulte la documentación oficial para más información:

    Puede obtener acceso a las propiedades del objeto de history y a la match más cercana de <Route> través del componente de orden superior withRouter. withRouter volverá a representar su componente cada vez que la ruta cambie con los mismos accesorios que <Route> render props: { match, location, history } .

  • Usa la API de context

    El uso del contexto podría ser una de las soluciones más fáciles, pero al ser una API experimental, es inestable y no es compatible. Úselo solo cuando todo lo demás falla. Aquí hay un ejemplo:

    import React from "react"; import PropTypes from "prop-types"; class MyComponent extends React.Component { static contextTypes = { router: PropTypes.object } constructor(props, context) { super(props, context); } ... myFunction() { this.context.router.history.push("/some/Path"); } ... }

    Echa un vistazo a la documentación oficial sobre contexto:

    Si desea que su aplicación sea estable, no use el contexto. Es una API experimental y es probable que se rompa en futuras versiones de React.

    Si insiste en usar el contexto a pesar de estas advertencias, intente aislar su uso del contexto en un área pequeña y evite usar la API de contexto directamente cuando sea posible para que sea más fácil actualizar cuando la API cambie.


React router V4 ahora permite utilizar el accesorio de historial de la siguiente manera:

this.props.history.push("/dummy",value)

Se puede acceder al valor siempre que el accesorio de ubicación esté disponible como state:{value} no estado del componente.


Si está utilizando Redux, entonces recomendaría usar el paquete npm react-router-redux . Le permite despachar acciones de navegación de la tienda Redux.

Debe crear la tienda como se describe en su react-router-redux .

El caso de uso más fácil:

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

Segundo caso de uso con contenedor / componente:

Envase:

import { connect } from ''react-redux''; import { push } from ''react-router-redux''; import Form from ''../components/Form''; const mapDispatchToProps = dispatch => ({ changeUrl: url => dispatch(push(url)), }); export default connect(null, mapDispatchToProps)(Form);

Componente:

import React, { Component } from ''react''; import PropTypes from ''prop-types''; export default class Form extends Component { handleClick = () => { this.props.changeUrl(''/secondPage''); }; render() { return ( <div> <button onClick={this.handleClick}/> </div>Readme file ); } }


Usar devolución de llamada. ¡Funcionó para mí!

export function addProduct(props, callback) { return dispatch => axios.post(`${ROOT_URL}/cart`, props, config) .then(response => { dispatch({ type: types.AUTH_USER }); localStorage.setItem(''token'', response.data.token); callback(); }); }

En el componente, solo tiene que agregar la devolución de llamada

this.props.addProduct(props, () => this.props.history.push(''/cart''))


así que la forma en que lo hago es: - en lugar de redirigir usando history.push , solo uso el componente Redirect de react-router-dom Cuando use este componente, puede pasar push=true y se encargará del resto

import * as React from ''react''; import { Redirect } from ''react-router-dom''; class Example extends React.Component { componentDidMount() { this.setState({ redirectTo: ''/test/path'' }); } render() { const { redirectTo } = this.state; return <Redirect to={{pathname: redirectTo}} push={true}/> } }


el primer paso envuelve tu aplicación en el enrutador

import { BrowserRouter as Router } from "react-router-dom"; ReactDOM.render(<Router><App /></Router>, document.getElementById(''root''));

Ahora toda mi aplicación tendrá acceso a BrowserRouter. Paso dos importo Ruta y luego paso esos accesorios. Probablemente en uno de tus archivos principales.

import { Route } from "react-router-dom"; //lots of code here //somewhere in my render function <Route exact path="/" //put what your file path is here render={props => ( <div> <NameOfComponent {...props} //this will pass down your match, history, location objects /> </div> )} />

Ahora, si ejecuto console.log (this.props) en mi archivo js de componente, debería obtener algo similar a esto

{match: {…}, location: {…}, history: {…}, //other stuff }

Paso 2 Puedo acceder al objeto de historial para cambiar mi ubicación

//lots of code here relating to my whatever request I just ran delete, put so on this.props.history.push("/") // then put in whatever url you want to go to

Además, solo soy un estudiante de programación de bootcamp, así que no soy un experto, pero sé que también puedes usar

window.location = "/" //wherever you want to go

Corrígeme si me equivoco, pero cuando lo probé, volvió a cargar toda la página, lo que pensé que derrotó el punto de usar React.


puedes usarlo así como lo hago para iniciar sesión y muchas cosas diferentes

class Login extends Component { constructor(props){ super(props); this.login=this.login.bind(this) } login(){ this.props.history.push(''/dashboard''); } render() { return ( <div> <button onClick={this.login}>login</login> </div> )


this.context.history.push no funcionará.

Me las arreglé para empujar trabajando así:

static contextTypes = { router: PropTypes.object } handleSubmit(e) { e.preventDefault(); if (this.props.auth.success) { this.context.router.history.push("/some/Path") } }


/*Step 1*/ myFunction(){ this.props.history.push("/home"); } /**/ <button onClick={()=>this.myFunction()} className={''btn btn-primary''}>Go Home</button>