Como fazer um redirecionamento para outra rota com react-router?

94

Estou tentando fazer um SIMPLE usando o react-router ( versão ^ 1.0.3 ) para redirecionar para outra visão e estou ficando cansado.

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;

tudo que eu preciso é enviar o uso para '/ login' e pronto.

O que eu posso fazer ?

erros no console:

ReferenceError não capturado: PropTypes não está definido

arquivo com minhas rotas

// 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>
);
Reagindo
fonte
Oi! Você pode postar suas routesdefinições, e também se há motivo para você não estar usando o Linkcomponente? Além disso, mencione quais erros você está recebendo.
aarosil de
Em vez de botão , <Link to="/login">Log In</Link>?
aarosil de
Além disso, qual versão do react-router você está usando? O código para redirecionamento de procedimento mudou entre as versões principais.
mjhm
4
Para o Uncaught ReferenceError, você está chamando como PropTypes, mas não importa isso, você precisa importar PropTypes como ele mesmo ou usarReact.PropTypes
aarosil
1
@JoshDavidMiller, bom ponto, no entanto, não ficarei surpreso com a react-routermudança da API em 5 minutos .. haha ​​está brincando, mas apenas parcialmente
aarosil

Respostas:

33

Para uma resposta simples, você pode usar o Linkcomponente de react-router, em vez de button. Existem maneiras de alterar a rota em JS, mas parece que você não precisa disso aqui.

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

Para fazer isso programaticamente em 1.0.x, você faz assim, dentro de sua função clickHandler:

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

Retirado do documento de atualização aqui

Você deve ter this.historycolocado em seu componente de manipulador de rota por react-router. Se for um componente filho abaixo do mencionado na routesdefinição, você pode precisar transmiti-lo mais adiante

arosila
fonte
2
esta é uma solução legal, mas a razão pela qual eu não estou usando é porque eu preciso fazer uma espécie de validação primeiro, então eu preciso colocar isso em uma função, como: if (true) { // redirect to login}é por isso que coloquei isso em um onClick função
Reagindo em
5
Você também pode fazer isso em JSX: {validation && <Link to="/login" />Click to login</Link>}. Se a validação for falsa, nada será renderizado.
aarosil de
Eu sei o que você quer dizer, mas eu preciso que o botão esteja lá, se a validação for verdadeira, então redirecione, caso contrário, uma mensagem de erro deve aparecer.
Reagindo em
@TheUnnamed atualizei a resposta para mostrar como fazê-lo em JS
aarosil
1
> Uncaught TypeError: Não é possível ler a propriedade 'pushState' de undefined
Reagindo em
92

1) react-router> useHistorygancho V5 :

Se você tiver React >= 16.8e componentes funcionais, você pode usar o useHistory gancho do 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 mencionou nos comentários, o React-router mudou sua base de código desde sua V4. Aqui estão as documentações - oficial , withRouter

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) Roteador React <V4 com browserHistory

Você pode obter essa funcionalidade usando o react-router BrowserHistory. Código abaixo:

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

Se você conectou seu componente com redux e configurou o roteador conectado-reagente, tudo o que você precisa fazer é this.props.history.push("/new/url");, ou seja, não precisa do withRouterHOC para injetar historynos props do 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
fonte
3
Parece que 'browserHistory' não faz mais parte do react-router.
Ambar
BrowserRouter não tem uma função push
johnnyodonnell
@ambar @johnnyodonnell react-router-domfaz
toinetoine
Esta é a melhor resposta. Você deve marcar este como o correto.
Solomon Bush
23

Como fazer um redirecionamento para outra rota com react-router?

Por exemplo, quando um usuário clica em um link, o <Link to="/" />Click to route</Link>react-router procura /e você pode usar Redirect toe enviar o usuário para outro lugar, como a rota de login.

Dos documentos para ReactRouterTraining :

Renderizar um <Redirect>irá navegar para um novo local. O novo local substituirá o local atual na pilha de histórico, como os redirecionamentos do lado do servidor (HTTP 3xx) fazem.

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

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

to: string, O URL para o qual redirecionar.

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

para: objeto, um local para o qual redirecionar.

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
jtlindsey
fonte
A solução fornecida gera um erro <Redirect> elements are for router configuration only and should not be rendered.
t1gor
9

A solução mais fácil para web!

Até a data de 2020
confirmou o trabalho com:

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

Use o 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
fonte
Excelente, estava procurando o jeito do gancho de fazer! Embora meu IDE indique o aviso "Não é possível resolver o símbolo ...", ele funciona!
Rafael Moni
7

Com o react-router v2.8.1 (provavelmente outras versões 2.xx também, mas não testei) você pode usar esta implementação para fazer um redirecionamento de roteador.

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
fonte
às vezes: this.context.router.history.push ('/ algum-caminho');
象 嘉 道
4

A solução mais simples é:

import { Redirect } from 'react-router';

<Redirect to='/componentURL' />
Jackkobec
fonte
Mas estou recebendo um erro: Falha invariável: você não deve usar <Redirecionar> fora de um <Roteador>
Prateek Gupta
Você tentou embrulhar?
Jackkobec