React-router v4 this.props.history.push(...) не работает

Я пытаюсь маршрутизировать программно с помощью this.props.history.push(..), но он не работает.

Здесь маршрутизатор:

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

<Router>
 <Route path="/customers/" exact component={CustomersList} />
 <Route path="/customers/:id" exact component="{Customer} />
</Router>

В CustomerList отображается список клиентов. Нажатие на клиента (li) должно сделать маршрут приложения к клиенту:

import { withRouter } from 'react-router'

class Customers extends Component {
  static propTypes = {
    history: PropTypes.object.isRequired
  }

 handleCustomerClick(customer) {
   this.props.history.push(`/customers/${customer.id}`);
 }

 render() {
   return(
    <ul>
      { this.props.customers.map((c) =>
        <li onClick={() => this.handleCustomerClick(c)} key={c.id}>
          {c.name}
        </li> 
    </ul>
  )

 }
}

//connect to redux to get customers

CustomersList = withRouter(CustomersList);
export default CustomersList;

Код является частичным, но в полной мере иллюстрирует ситуацию. Случается, что адресная строка браузера изменяется в соответствии с history.push(..), но представление не обновляется, компонент Customer не отображается, а CustomerList все еще существует. Любые идеи?

Ответ 1

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

const { history } = this.props;
history.push("/thePath")

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

Найти рабочую песочницу здесь

  • история: v4.7.2
  • реагировать: v16.0.0
  • Реакт-Дом: v16.0.0
  • response-router-dom: v4.2.2

Ответ 2

Кажется, что в последней версии реагирующего маршрутизатора ситуация немного изменилась. Теперь вы можете получить доступ к истории через контекст. this.context.history.push('/path')

Также см. ответы на эту проблему github: https://github.com/ReactTraining/react-router/issues/4059

Ответ 3

Вы можете попробовать загрузить дочерний компонент с историей. Для этого пропустите "историю" через реквизит. Что-то вроде того:

  return (
  <div>
    <Login history={this.props.history} />
    <br/>
    <Register/>
  </div>
)

Ответ 4

Похоже, старый вопрос, но все еще актуален.

Я думаю, что это заблокированная проблема обновления.

Основная проблема заключается в том, что новый URL (маршрут) должен отображаться тем же компонентом (Costumers), который используется в данный момент (текущий URL).

Таким образом, решение довольно простое, сделайте URL окна в качестве реквизита, чтобы у реакции был шанс обнаружить изменение реквизита (и, следовательно, изменение URL), и действовать соответственно.

Хороший пример использования, описанный в официальном блоге реакции, называется " Рекомендация: полностью неконтролируемый компонент с ключом".

Таким образом, решение состоит в том, чтобы перейти от render() { return(<ul>

to render() { return(<ul key={this.props.location.pathname}>

Таким образом, всякий раз, когда местоположение изменяется в реагирующем маршрутизаторе, компонент удаляется (по реакции), и новое инициируется с правильными значениями (по реакции).

Да, и передайте location качестве реквизита компоненту (Costumers), где произойдет перенаправление, если оно еще не передано.

Надеюсь, это поможет кому-то.

Ответ 5

Для меня (реакции-маршрутизатор v4, реагируйте v16) проблема заключалась в том, что у меня был компонент навигации в порядке:

import { Link, withRouter } from 'react-router-dom'

class MainMenu extends Component {

  render() {
    return (
            ...
            <NavLink to="/contact">Contact</NavLink>
            ...
    );
  }
}

export default withRouter(MainMenu);

Оба используют либо

to="/contact" 

или же

OnClick={() => this.props.history.push('/contact')}; 

Поведение было таким же - URL в браузере изменился, но были отображены неправильные компоненты, маршрутизатор был вызван с тем же старым URL.

Виновник был в определении роутера. Мне пришлось переместить компонент MainMenu как дочерний компонент компонента Router!

// wrong placement of the component that calls the router
<MainMenu history={this.props.history} />
<Router>
   <div>
     // this is the right place for the component!
     <MainMenu history={this.props.history} />
     <Route path="/" exact component={MainPage} />
     <Route path="/contact/" component={MainPage} />
   </div>
</Router>

Ответ 6

Не используйте с маршрутизатором.

handleSubmit(e){
   e.preventDefault();
   this.props.form.validateFieldsAndScroll((err,values)=>{
      if(!err){
        this.setState({
            visible:false
        });
        this.props.form.resetFields();
        console.log(values.username);
        const path = '/list/';
        this.props.history.push(path);
      }
   })
}

Хорошо работает.

Ответ 7

Вам необходимо экспортировать клиентский компонент, а не CustomerList.

    CustomersList = withRouter(Customers);
    export default CustomersList;

Ответ 8

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

import React, { Component } from 'react'
import { withRouter } from 'react-router'; 
// you can also import "withRouter" from 'react-router-dom';

class Example extends Component {
    render() {
        const { match, location, history } = this.props
        return (
            <div>
                <div>You are now at {location.pathname}</div>
                <button onClick={() => history.push('/')}>{'Home'}</button>
            </div>
        )
    }
}


export default withRouter(Example)

Ответ 9

Давай рассмотрим этот сценарий. У вас есть App.jsx в качестве корневого файла для ReactJS SPA. В этом ваш render() выглядит примерно так:

<Switch>
    <Route path="/comp" component={MyComponent} />
</Switch>

тогда вы сможете без проблем использовать this.props.history внутри MyComponent. Допустим, вы визуализируете MySecondComponent внутри MyComponent, в этом случае вам нужно вызвать его следующим образом:

<MySecondComponent {...props} />

который передаст реквизит от MyComponent до MySecondComponent, тем самым сделав this.props.history доступным в MySecondComponent

Ответ 10

Вам необходимо связать handleCustomerClick:

class Customers extends Component {
  constructor() {
    super();
    this.handleCustomerClick = this.handleCustomerClick(this)
  }

Ответ 11

this.props.history.push('/customers/${customer.id}', null);