¿Cómo hacer una redirección a otra ruta con react-router?

95

Estoy tratando de hacer UN SIMPLE usando react-router ( versión ^ 1.0.3 ) para redirigir a otra vista y me estoy cansando.

import React from 'react';
import {Router, Route, Link, RouteHandler} from 'react-router';


class HomeSection extends React.Component {

  static contextTypes = {
    router: PropTypes.func.isRequired
  };

  constructor(props, context) {
    super(props, context);
  }

  handleClick = () => {
    console.log('HERE!', this.contextTypes);
    // this.context.location.transitionTo('login');
  };

  render() {
    return (
      <Grid>
        <Row className="text-center">          
          <Col md={12} xs={12}>
            <div className="input-group">
              <span className="input-group-btn">
                <button onClick={this.handleClick} type="button">
                </button>
              </span>
            </div>
          </Col>
        </Row>
      </Grid>
    );
  }
};

HomeSection.contextTypes = {
  location() {
    React.PropTypes.func.isRequired
  }
}

export default HomeSection;

todo lo que necesito es enviar el uso a '/ login' y eso es todo.

Que puedo hacer ?

errores en la consola:

Error de referencia no detectado: PropTypes no está definido

archivo con mis rutas

// LIBRARY
/*eslint-disable no-unused-vars*/
import React from 'react';
/*eslint-enable no-unused-vars*/
import {Route, IndexRoute} from 'react-router';

// COMPONENT
import Application from './components/App/App';
import Contact from './components/ContactSection/Contact';
import HomeSection from './components/HomeSection/HomeSection';
import NotFoundSection from './components/NotFoundSection/NotFoundSection';
import TodoSection from './components/TodoSection/TodoSection';
import LoginForm from './components/LoginForm/LoginForm';
import SignupForm from './components/SignupForm/SignupForm';

export default (
    <Route component={Application} path='/'>
      <IndexRoute component={HomeSection} />
      <Route component={HomeSection} path='home' />
      <Route component={TodoSection} path='todo' />
      <Route component={Contact} path='contact' />
      <Route component={LoginForm} path='login' />
      <Route component={SignupForm} path='signup' />
      <Route component={NotFoundSection} path='*' />
    </Route>
);
Reaccionando
fuente
¡Hola! ¿Puede publicar sus routesdefiniciones y también si hay una razón por la que no está utilizando el Linkcomponente? Además, mencione qué errores está recibiendo.
aarosil
En lugar de botón <Link to="/login">Log In</Link>,?
aarosil
Además, ¿qué versión de react-router estás usando? El código para la redirección de procedimientos ha cambiado entre las versiones principales.
mjhm
4
Para el Uncaught ReferenceError, está llamando como PropTypes, pero no importa eso, necesita importar PropTypes como él mismo o usarReact.PropTypes
aarosil
1
@JoshDavidMiller buen punto, sin embargo, no me sorprenderá el react-routercambio de api en 5 minutos ... jaja es broma, pero solo parcialmente
aarosil

Respuestas:

33

Para obtener una respuesta simple, puede usar el Linkcomponente de react-router, en lugar de button. Hay formas de cambiar la ruta en JS, pero parece que no las necesita aquí.

<span className="input-group-btn">
  <Link to="/login" />Click to login</Link>
</span>

Para hacerlo programáticamente en 1.0.x, te gusta esto, dentro de tu función clickHandler:

this.history.pushState(null, 'login');

Tomado del documento de actualización aquí

Debería haber this.historycolocado en su componente controlador de ruta por react-router. Si el componente secundario está debajo del mencionado en la routesdefinición, es posible que deba transmitirlo más

aarosil
fuente
2
esta es una solución genial, pero la razón por la que no la estoy usando es porque primero necesito hacer una especie de validación, así que necesito poner esto en una función, como: if (true) { // redirect to login}por eso puse eso en un onClick función
Reaccionando el
5
También puede hacer que en JSX: {validation && <Link to="/login" />Click to login</Link>}. Si la validación es falsa, no se generará nada.
aarosil
Sé lo que quieres decir, pero necesito que el botón esté allí, si la validación es verdadera, redirigir, de lo contrario debería aparecer un mensaje de error.
Reaccionando el
@TheUnnamed Actualicé la respuesta para mostrar cómo hacerlo en JS
aarosil
1
> Error de tipo no detectado: no se puede leer la propiedad 'pushState' de undefined
Reaccionando el
95

1) react-router> V5 useHistoryhook:

Si tiene React >= 16.8componentes funcionales, puede usar el useHistory enlace de react-router .

import React from 'react';
import { useHistory } from 'react-router-dom';

const YourComponent = () => {
    const history = useHistory();

    const handleClick = () => {
        history.push("/path/to/push");
    }

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

export default YourComponent;

2) react-router> V4 withRouterHOC:

Como @ambar mencionó en los comentarios, React-router ha cambiado su base de código desde su V4. Aquí están las documentaciones - oficial , conRouter

import React, { Component } from 'react';
import { withRouter } from "react-router-dom";

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

export default withRouter(YourComponent);

3) React-router <V4 con browserHistory

Puede lograr esta funcionalidad utilizando react-router BrowserHistory. Código a continuación:

import React, { Component } from 'react';
import { browserHistory } from 'react-router';

export default class YourComponent extends Component {
    handleClick = () => {
        browserHistory.push('/login');
    };

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

4) Redux connected-react-router

Si ha conectado su componente con redux y ha configurado connected-react-router, todo lo que tiene que hacer es es this.props.history.push("/new/url");decir, no necesita withRouterHOC para inyectar historylos accesorios del componente.

// reducers.js
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';

export default (history) => combineReducers({
    router: connectRouter(history),
    ... // rest of your reducers
});


// configureStore.js
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers';
...
export const history = createBrowserHistory();

export default function configureStore(preloadedState) {
    const store = createStore(
        createRootReducer(history), // root reducer with router state
        preloadedState,
        compose(
            applyMiddleware(
                routerMiddleware(history), // for dispatching history actions
                // ... other middlewares ...
            ),
        ),
    );

    return store;
}


// set up other redux requirements like for eg. in index.js
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router';
import { ConnectedRouter } from 'connected-react-router';
import configureStore, { history } from './configureStore';
...
const store = configureStore(/* provide initial state if any */)

ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <> { /* your usual react-router v4/v5 routing */ }
                <Switch>
                    <Route exact path="/yourPath" component={YourComponent} />
                </Switch>
            </>
        </ConnectedRouter>
    </Provider>,
    document.getElementById('root')
);


// YourComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
...

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
          <div>
            <button onClick={this.handleClick} type="button">
          </div>
        );
      }
    };

}

export default connect(mapStateToProps = {}, mapDispatchToProps = {})(YourComponent);
Noushad
fuente
3
Parece que 'browserHistory' ya no forma parte de react-router.
Ambar
BrowserRouter no tiene una función de empuje
johnnyodonnell
@ambar @johnnyodonnell react-router-domdoes
toinetoine
Esta es la mejor respuesta. Debes marcar este como el correcto.
Solomon Bush
23

¿Cómo hacer una redirección a otra ruta con react-router?

Por ejemplo, cuando un usuario hace clic en un enlace, <Link to="/" />Click to route</Link>react-router buscará /y puede usarRedirect to y enviar al usuario a otro lugar como la ruta de inicio de sesión.

De los documentos de ReactRouterTraining :

Al renderizar, <Redirect>se navegará a una nueva ubicación. La nueva ubicación anulará la ubicación actual en la pila del historial, como lo hacen los redireccionamientos del lado del servidor (HTTP 3xx).

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

to: string, la URL a la que se redirecciona.

<Redirect to="/somewhere/else"/>

to: object, Una ubicación a la que redireccionar.

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
jtlindsey
fuente
La solución proporcionada arroja un error <Redirect> elements are for router configuration only and should not be rendered.
t1gor
10

Más fácil solución sencilla para la web!

Hasta la fecha 2020
confirmado trabajando con:

"react-router-dom": "^5.1.2"
"react": "^16.10.2"

¡Usa el useHistory()gancho!

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


export function HomeSection() {
  const history = useHistory();
  const goLogin = () => history.push('login');

  return (
    <Grid>
      <Row className="text-center">          
        <Col md={12} xs={12}>
          <div className="input-group">
            <span className="input-group-btn">
              <button onClick={goLogin} type="button" />
            </span>
          </div>
        </Col>
      </Row>
    </Grid>
  );
}
Scott Plunkett
fuente
Excelente, estaba buscando la forma de gancho para hacerlo! Aunque mi IDE indica la advertencia "No se puede resolver el símbolo ...", ¡funciona!
Rafael Moni
7

Con react-router v2.8.1 (probablemente otras versiones 2.xx también, pero no las he probado) puede usar esta implementación para hacer una redirección de enrutador.

import { Router } from 'react-router';

export default class Foo extends Component {

  static get contextTypes() {
    return {
      router: React.PropTypes.object.isRequired,
    };
  }

  handleClick() {
    this.context.router.push('/some-path');
  }
}
Tom Van Rompaey
fuente
a veces: this.context.router.history.push ('/ alguna-ruta');
象 嘉 道
4

La solución más sencilla es:

import { Redirect } from 'react-router';

<Redirect to='/componentURL' />
Jackkobec
fuente
Pero recibo un error: Invariante fallido: no debe usar <Redirect> fuera de un <Router>
Prateek Gupta
¿Intentaste envolver?
Jackkobec