Como obter o histórico do react-router v4?

101

Estou tendo um pequeno problema ao migrar do React-Router v3 para v4. na v3, consegui fazer isso em qualquer lugar:

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

Como faço para conseguir isso na v4.

Eu sei que poderia usar o hoc withRouter, o contexto de reação ou os adereços do roteador de evento quando você estiver em um componente. mas não é o meu caso.

Estou procurando a equivalência de NavigatingOutsideOfComponents na v4

storm_buster
fonte
1
Obrigado @Chris, mas como eu disse, não estou no Component.
storm_buster,
@Chris em uma classe de utilitário, por favor, verifique github.com/ReactTraining/react-router/blob/master/docs/guides/… , poderia ter sido um redux middlewarere ou qualquer outra coisa
storm_buster
maneira mais simples stackoverflow.com/a/53916596/3966458
Saahithyan Vigneswaran
Acabei usando o BrowserRouter como componente raiz. Dessa forma, eu poderia usar o componente App com o roteador. Não é exatamente o que você pediu, mas tenho os mesmos requisitos e isso é suficiente para mim.
The Fool

Respostas:

180

Você só precisa ter um módulo que exporte um historyobjeto. Em seguida, você importaria esse objeto em todo o projeto.

// history.js
import { createBrowserHistory } from 'history'

export default createBrowserHistory({
  /* pass a configuration object here if needed */
})

Então, em vez de usar um dos roteadores embutidos, você usaria o <Router>componente.

// index.js
import { Router } from 'react-router-dom'
import history from './history'
import App from './App'

ReactDOM.render((
  <Router history={history}>
    <App />
  </Router>
), holder)
// some-other-file.js
import history from './history'
history.push('/go-here')
Paul S
fonte
1
Muito obrigado! No momento, usando react-router4, eu tinha que usar esta importação em history.js: import createBrowserHistory from 'history / createBrowserHistory';
peter.bartos
3
Funcionou para mim quando coloquei história = {história} na Rota e passei como um adereço
Nath Paiva
1
podemos usar withHistory e obter o histórico em adereços em vez de criar um arquivo separado. esta solução não funcionou para mim com redux.
Zeel Shah
4
Importe createHashHistoryse você estiver usando HashRouter.
David Harkness
2
@HassanAzzam Você provavelmente está usando o react-router V5 e esta resposta funciona para V4, não V5. Tenho agora o mesmo desafio e estou procurando em todos os lugares, mas não consigo fazer funcionar. history.push fora do componente funciona, mas os cliques no link não funcionam mais.
Waterlink
71

Isso funciona! https://reacttraining.com/react-router/web/api/withRouter

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

class MyComponent extends React.Component {
  render () {
    this.props.history;
  }
}

withRouter(MyComponent);
Justin Yueh
fonte
27
contanto que você esteja em um componente. Não estou em um componente
storm_buster de
1
Obrigado, esta é a maneira mais fácil e direta de vincular a outra rota a partir de um componente. Gostaria apenas de acrescentar que você precisa fazer this.props.history.push('/some_route');para que funcione.
dannytenaglias
1
@storm_buster const Component = props => {... // stuff}e export default withRouter(Component)funciona para mim em um componente sem estado
Karl Taylor
10

Semelhante a uma resposta aceita, o que você poderia fazer é usar reacte react-routerse fornecer a vocêhistory objeto que você pode acessar em um arquivo e depois exportar.

history.js

import React from 'react';
import { withRouter } from 'react-router';

// variable which will point to react-router history
let globalHistory = null;

// component which we will mount on top of the app
class Spy extends React.Component {
  constructor(props) {
    super(props)
    globalHistory = props.history; 
  }

  componentDidUpdate() {
    globalHistory = this.props.history;
  }

  render(){
    return null;
  }
}

export const GlobalHistory = withRouter(Spy);

// export react-router history
export default function getHistory() {    
  return globalHistory;
}

Mais tarde, você importa o componente e monta para inicializar a variável de histórico:

import { BrowserRouter } from 'react-router-dom';
import { GlobalHistory } from './history';

function render() {
  ReactDOM.render(
    <BrowserRouter>
        <div>
            <GlobalHistory />
            //.....
        </div>
    </BrowserRouter>
    document.getElementById('app'),
  );
}

E então você pode simplesmente importar em seu aplicativo quando ele tiver sido montado:

import getHistory from './history'; 

export const goToPage = () => (dispatch) => {
  dispatch({ type: GO_TO_SUCCESS_PAGE });
  getHistory().push('/success'); // at this point component probably has been mounted and we can safely get `history`
};

Eu até fiz um pacote npm que faz exatamente isso.

Tomasz Mularczyk
fonte
A partir da versão 16.9, esta solução emitirá um aviso de depreciação em componentWillMount e componentWillReceiveProps.
ian
1
@ian true, consertou isso
Tomasz Mularczyk
5

Se você estiver usando redux e redux-thunk a melhor solução será usar react-router-redux

// then, in redux actions for example
import { push } from 'react-router-redux'

dispatch(push('/some/path'))

É importante ver a documentação para fazer algumas configurações.

Arnold Gandarillas
fonte
1
Vim aqui na esperança de encontrar esta solução exata, obrigado
vapurrmaid
4

Com base nesta resposta, se você precisar do objeto de histórico apenas para navegar para outro componente:

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>
  );
}
Konrad Grzyb
fonte
ERRADO, você está dentro de um componente. veja // algum-outro-arquivo.js na resposta aceita
storm_buster,
0

Em App.js

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

 const TheContext = React.createContext(null);

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

   <TheContext.Provider value={{ history, user }}>

    <Switch>
        <Route exact path="/" render={(props) => <Home {...props} />} />
        <Route
          exact
          path="/sign-up"
          render={(props) => <SignUp {...props} setUser={setUser} />}
        /> ...

Então, em um componente filho:

const Welcome = () => {
    
    const {user, history} = React.useContext(TheContext); 
    ....
Esquilo
fonte
-2

No caso específico de react-router, usar contexté um cenário de caso válido, por exemplo

class MyComponent extends React.Component {
  props: PropsType;

  static contextTypes = {
    router: PropTypes.object
  };

  render () {
    this.context.router;
  }
}

Você pode acessar uma instância do histórico por meio do contexto do roteador, por exemplo this.context.router.history.

Gajus
fonte
A questão especificamente é perguntar sobre quando fora de um componente, portanto this.context não está disponível como uma opção:> "Eu sei que eu poderia usar o hoc withRouter, o contexto de reação ou props de roteador de evento quando você estiver em um componente. Mas não é o meu caso. "
SunshinyDoyle