Jak uzyskać historię na React-router v4?


103

Mam mały problem z migracją z React-Router v3 do v4. w wersji 3 mogłem to zrobić wszędzie:

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

Jak mogę to osiągnąć w v4.

Wiem, że mógłbym użyć withRouterrekwizytów hoc , kontekstu reakcji lub routera zdarzeń, gdy jesteś w komponencie. ale tak nie jest w przypadku mnie.

Szukam równoważności NavigatingOutsideOfComponents w v4


1
Dzięki @Chris, ale jak powiedziałem, nie jestem w komponencie.
storm_buster

@Chris w klasie użytkowej, sprawdź github.com/ReactTraining/react-router/blob/master/docs/guides/… , mogło to być oprogramowanie pośredniczące Redux lub cokolwiek innego
storm_buster


Skończyło się na używaniu BrowserRouter jako komponentu głównego. W ten sposób mogłem użyć komponentu aplikacji z routerem. Nie do końca to, o co prosiłeś, ale mam takie same wymagania i to mi wystarcza.
The Fool

Odpowiedzi:


182

Wystarczy mieć moduł eksportujący historyobiekt. Następnie możesz zaimportować ten obiekt w całym projekcie.

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

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

Wtedy zamiast używać jednego z wbudowanych routerów, użyjesz <Router>komponentu.

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

1
Wielkie dzięki! W tej chwili, używającreak-router4, musiałem zamiast tego użyć tego importu w history.js: import createBrowserHistory z 'history / createBrowserHistory';
peter.bartos

3
To zadziałało, kiedy umieściłem historię = {history} w Route i przechodzę jak rekwizyty
Nath Paiva

1
możemy użyć withHistory i pobrać historię w rekwizytach, zamiast tworzyć osobny plik. to rozwiązanie nie działało dla mnie z Reduxem.
Zeel Shah

4
Importuj, createHashHistoryjeśli używasz HashRouter.
David Harkness

2
@HassanAzzam Prawdopodobnie używasz reaktywowanego routera V5, a ta odpowiedź działa dla V4, a nie V5. Mam teraz to samo wyzwanie i szukam wszędzie, ale nie mogę tego zrobić. history.push poza komponentem działa, ale kliknięcia linku już nie.
Waterlink

71

To działa! 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);

27
tak długo, jak jesteś w komponencie. Nie jestem w komponencie
storm_buster

1
Dziękuję, to najłatwiejszy i najprostszy sposób na połączenie z inną trasą z komponentu. Dodam tylko, że trzeba to zrobić, this.props.history.push('/some_route');żeby to zadziałało.
dannytenaglias

1
@storm_buster const Component = props => {... // stuff}i export default withRouter(Component)pracuje dla mnie nad składnikiem bezstanowym
Karl Taylor,

11

Podobnie do zaakceptowanej odpowiedzi, co możesz zrobić, to użyć reacti react-routersamego w celu dostarczenia historyobiektu, który możesz określić w pliku, a następnie wyeksportować.

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

Następnie importujesz komponent i montujesz, aby zainicjować zmienną historii:

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

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

A potem możesz po prostu zaimportować do swojej aplikacji po jej zamontowaniu:

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

Zrobiłem nawet pakiet npm , który właśnie to robi.


Począwszy od reagjs 16.9, to rozwiązanie wyrzuci ostrzeżenie o przestarzałości w składnikach componentWillMount i componentWillReceiveProps.
ian

1
@ian prawda, naprawiłem to
Tomasz Mularczyk

5

Jeśli używasz redux i redux-thunk, najlepszym rozwiązaniem będzie reakcja-router-redux

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

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

Aby dokonać pewnych konfiguracji, należy zapoznać się z dokumentami.


1
Przyszedłem tutaj z nadzieją, że znajdę to dokładne rozwiązanie, dziękuję
vapurrmaid

4

Bazując na tej odpowiedzi, jeśli potrzebujesz obiektu historii tylko w celu przejścia do innego komponentu:

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

ŹLE, jesteś wewnątrz komponentu. zobacz // some-other-file.js z zaakceptowanej odpowiedzi
storm_buster

0

W 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} />}
        /> ...

Następnie w komponencie podrzędnym:

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

-2

W konkretnym przypadku react-routerużycie contextjest ważnym scenariuszem, np

class MyComponent extends React.Component {
  props: PropsType;

  static contextTypes = {
    router: PropTypes.object
  };

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

Możesz uzyskać dostęp do instancji historii poprzez kontekst routera, np this.context.router.history.


Pytanie dotyczy konkretnie sytuacji poza komponentem, więc this.context nie jest dostępna jako opcja:> „Wiem, że mógłbym użyć hoc z routerem, kontekstu reakcji lub rekwizytów routera zdarzeń, gdy jesteś w komponencie. Ale w moim przypadku tak nie jest ”.
SunshinyDoyle
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.