Как получить историю на react-router v4?

103

У меня возникла небольшая проблема с переходом с React-Router v3 на v4. в v3 я мог делать это где угодно:

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

Как мне добиться этого в v4.

Я знаю, что могу использовать свойства hoc withRouter, контекста реакции или маршрутизатора событий, когда вы находитесь в компоненте. но для меня это не так.

Я ищу эквивалент NavigatingOutsideOfComponents в v4

storm_buster
источник
1
Спасибо @Chris, но, как я уже сказал, я не в Component.
storm_buster 08
@Chris в служебном классе, пожалуйста, проверьте github.com/ReactTraining/react-router/blob/master/docs/guides/… , это могло быть промежуточное ПО
redux
самый
В итоге я использовал BrowserRouter в качестве корневого компонента. Таким образом, я мог использовать компонент App с Router. Не совсем то, что вы просили, но у меня те же требования, и этого мне достаточно.
The Fool

Ответы:

182

Вам просто нужен модуль, который экспортирует historyобъект. Затем вы должны импортировать этот объект в свой проект.

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

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

Затем вместо использования одного из встроенных маршрутизаторов вы должны использовать <Router>компонент.

// 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
Большое спасибо! На данный момент, используя response-router4, мне пришлось вместо этого использовать этот импорт в history.js: import createBrowserHistory from 'history / createBrowserHistory';
peter.bartos
3
У меня это сработало, когда я поместил history = {history} в Route и передал его как реквизит
Нат Пайва
1
мы можем использовать withHistory и получать историю в реквизитах, а не создавать отдельный файл. это решение не сработало для меня с redux.
Zeel Shah
4
Импортируйте, createHashHistoryесли вы использовали HashRouter.
Дэвид Харкнесс
2
@HassanAzzam Вы, вероятно, используете реактивный маршрутизатор V5, и этот ответ работает для V4, а не для V5. У меня сейчас та же проблема, и я ищу везде, но не могу заставить ее работать. history.push вне компонента работает, но щелчки по ссылке больше не работают.
Waterlink
71

Это работает! 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
пока вы находитесь в компоненте. Я не в компоненте
storm_buster
1
Спасибо, это самый простой и понятный способ связать с другим маршрутом из компонента. Я бы просто добавил, что нужно сделать, this.props.history.push('/some_route');чтобы это работало.
dannytenaglias
1
@storm_buster const Component = props => {... // stuff}и export default withRouter(Component)работает для меня над компонентом без сохранения состояния
Карл Тейлор
11

По аналогии с принятым ответом вы могли бы использовать reactи react-routerсам, чтобы предоставить вам historyобъект, который вы можете указать в файле, а затем экспортировать.

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

Позже вы импортируете компонент и монтируете его для инициализации переменной истории:

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

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

А затем вы можете просто импортировать в свое приложение, когда оно было смонтировано:

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

Я даже сделал и пакет npm, который делает именно это.

Томаш Муларчик
источник
Начиная с responsejs 16.9, это решение будет выдавать предупреждение об устаревании для componentWillMount и componentWillReceiveProps.
ian
1
@ian true, исправил это
Томаш Муларчик
5

Если вы используете redux и redux-thunk, лучшим решением будет использовать response-router-redux

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

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

Для некоторых настроек важно ознакомиться с документацией.

Арнольд Гандариллас
источник
1
Я пришел сюда в надежде найти это точное решение, спасибо
vapurrmaid
4

Основываясь на этом ответе, если вам нужен объект истории только для перехода к другому компоненту:

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>
  );
}
Конрад Гржиб
источник
НЕПРАВИЛЬНО, вы находитесь внутри компонента. см. // some-other-file.js из принятого ответа
storm_buster
0

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

Затем в дочернем компоненте:

const Welcome = () => {
    
    const {user, history} = React.useContext(TheContext); 
    ....
Белка
источник
-2

В конкретном случае react-routerиспользование contextявляется допустимым сценарием, например

class MyComponent extends React.Component {
  props: PropsType;

  static contextTypes = {
    router: PropTypes.object
  };

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

Вы можете получить доступ к экземпляру истории через контекст маршрутизатора, например this.context.router.history.

Gajus
источник
В частности, вопрос заключается в том, когда вы находитесь вне компонента, поэтому this.context недоступен в качестве опции:> «Я знаю, что могу использовать hoc withRouter, контекст реакции или свойства маршрутизатора событий, когда вы находитесь в компоненте. Но для меня это не так ".
SunshinyDoyle