Навигация по программному обеспечению в React-Router v4

Я не мог дождаться, и я вскочил с использованием последней альфа-версии react-router v4. Все новый <BrowserRouter/> отлично поддерживает синхронизацию вашего пользовательского интерфейса с историей браузера, но как его использовать для навигации по программному обеспечению?

Ответ 1

Маршрутизатор добавит history объекта компонента в props хэш. Так что в вашем компоненте просто сделайте:

this.props.history.push('/mypath')

Вот полный пример:

В App.js:

import React from 'react'
import {BrowserRouter as Router, Route} from 'react-router-dom'

import Login from './Login'

export default class App extends React.Component {
  render() {
    return (
      <Router>
        <div>
          <Route exact path='/login' component={Login} />
        </div>
      </Router>
    )
  }
}

В Login.js:

import React, {PropTypes} from 'react'

export default class Login extends React.Component {
  constructor(props) {
    super(props)
    this.handleLogin = this.handleLogin.bind(this)
  }

  handleLogin(event) {
    event.preventDefault()
    // do some login logic here, and if successful:
    this.props.history.push('/mypath')
  }

  render() {
    return (
      <div>
        <form onSubmit={this.handleLogin}>
          <input type='submit' value='Login' />
        </form>
      </div>
    )
  }
}

Ответ 2

В прошлом вы могли использовать browserHistory для ввода нового пути. Это не будет работать с react-router v4. Вместо этого вы используете метод React context и router transitionTo.

Вот простой пример:

import React from 'react';

class NavigateNext extends React.Component {
  constructor() {
    super();
    this.navigateProgramatically = this.navigateProgramatically.bind(this);
  }

  navigateProgramatically(e) {
    e.preventDefault();

    this.context.router.transitionTo(e.target.href)
  }

  render() {
    return (
      <Link to={"/next-page"}
            onClick={this.navigateProgramatically}
      >Continue</Link>
    );
  }
}

NavigateNext.contextTypes = {
  router: React.PropTypes.object
};

transitionTo - только один из доступных методов router. router объект также содержит blockTransitions(getPromptMessage), createHref(to) и replaceWith(loc), которые стоит проверить.

Здесь официальный react-router учебник, который упоминает выше метод. Если вы хотите узнать больше об использовании react context, просмотрите docs.

Ответ 3

У меня недостаточно репутации для комментариев, но в ответ на вопрос @singularity вам нужно включить свойства контекста, которые вы хотите сделать доступными в статическом свойстве класса contextTypes.

Из React docs на context:

Если contextTypes не определен, то контекст будет пустым.

В этом случае:

class NavigateNext extends React.Component {

  // ...

  static contextTypes = {
    router: PropTypes.object
  }

  // ...

}

В отличие от propTypes, contextTypes на самом деле заставляют React вести себя по-другому и не только для проверки типов.

Ответ 4

Используя withRouter, вы добавите свойства маршрутизатора к вашему компоненту, затем вы можете получить доступ к history и использовать push, как вы это делали с v3:

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

class Form extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      input: '',
    };

    this._submit = this._submit.bind(this);
  }

  render() {
    return (
      <form onSubmit={this._submit}>
        <input type="text" onChange={(event) => this.setState({input: event.target.value})}/>

        <button type="submit">Submit</button>
      </form>
    );
  }

  _submit(event) {
    event.preventDefault();

    this.props.history.push(`/theUrlYouWantToGoTo`);
  }
}

export default withRouter(Form);

Ответ 5

бета-версия реакции-маршрутизатора v4 и API немного изменился. Вместо this.context.router.transitionTo(e.target.href) Do, this.context.router.push(e.target.href), если вы используете последнюю версию.

Ссылка на новый документ: https://reacttraining.com/react-router/#context.router

Ответ 6

Если вам нужно перейти за пределы компонента в том месте, которое невозможно передать в объекте истории из компонента, аналогичного тому, как вы это делали бы с браузером в старых версиях, вы можете сделать следующее.

Сначала создайте модуль истории

History.js:

import createBrowserHistory from 'history/createBrowserHistory'

export default createBrowserHistory();

Затем, когда вы объявляете маршрутизатор, обязательно импортируйте Router из реактора-маршрутизатора, а не response-router-dom (который является просто оболочкой для версии с реакцией-маршрутизатором, но автоматически создает объект истории) и передайте в модуль истории вы только что созданный

Root.js(или везде, где вы это делаете):

import Router from 'react-router/Router'
import history from './history'

...

class Root extends Component{
  render() {
    return (
      <Router history={history}>
        ...
      </Router>
    );
  }
}

Теперь ваше приложение будет использовать созданную вами историю создания. Теперь вы можете импортировать этот модуль истории в любом месте и просто сделать history.replace и т.д. Так же, как и в прошлом с историей браузера.

SomeModule.js:

import history from './history';

export default ()=>{
  // redirecting to login page using history without having to pass it in 
  // from a component
  history.replace('/login')
}

Конечно, это не рекомендуется, так как использование браузера в старых версиях не было рекомендуемым, так как такие вещи, как рендеринг на стороне сервера, не будут работать, но если вам все равно, это часто может быть правильным решение.

Дополнительным преимуществом этого является то, что вы могли бы увеличить объект истории до того, что в нем были проанализированы параметры строки запроса, например:

import createBrowserHistory from 'history/createBrowserHistory'
import queryString from 'query-string';

const history = createBrowserHistory();

history.location.query = queryString.parse(history.location.search);

history.listen(() => {
  history.location.query = queryString.parse(history.location.search);
});

export default history;

Ответ 7

Если вам нужен доступ к истории за пределами компонентов (например, в действиях с избыточностью), Reaction-router опубликовал свое оригинальное решение здесь.

По сути, вы должны создать свой собственный объект истории:

import { createBrowserHistory } from 'history';

const history = createBrowserHistory();

И передайте это вашему маршрутизатору:

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

ReactDOM.render((
  <Router history={history}> // <<-- the history object
    <App/>
  </Router>
), document.getElementById('root'))

Примечание: вы должны использовать обычный Router вместо BrowserRouter или HashRouter здесь!

Если вы экспортируете history сейчас, вы можете работать с ней где угодно:

import history from './history';

history.push('/home');

Ответ 8

Я нашел, используя состояние, тройной оператор и <Redirect> работал лучше всего. Я думаю, что это также предпочтительный путь, поскольку он ближе всего к настройке v4.

В конструкторе()

this.state = {
    redirectTo: null
} 
this.clickhandler = this.clickhandler.bind(this);

В render()

render(){
    return (
        <div>
        { this.state.redirectTo ?
            <Redirect to={{ pathname: this.state.redirectTo }} /> : 
            (
             <div>
               ..
             <button onClick={ this.clickhandler } />
              ..
             </div>
             )
         }

В clickhandler()

 this.setState({ redirectTo: '/path/some/where' });

Надеюсь, это поможет. Дайте мне знать.

Ответ 9

используйте withRouter:

import React, { PropTypes } from 'react'
import { withRouter } from 'react-router'

// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  }

  render() {
    const { match, location, history } = this.props

    return (
      <div>You are now at {location.pathname}</div>
    )
  }
}

// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)

Ответ 10

Это действительно сложно с реакцией-роутером. Ни один из вариантов не прост. this.props.history дал мне undefined. Но

window.location='/mypath/';

у меня работало в version 5.0.0. Не знаю, правильный ли это метод.