React-router v4 this.props.history.push(...)无效

时间:2017-06-01 16:08:35

标签: reactjs react-router react-redux

我尝试使用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组件未呈现且CustomersList仍然存在。有什么想法吗?

14 个答案:

答案 0 :(得分:11)

在最新版本的反应路由器中似乎发生了一些变化。您现在可以通过上下文访问历史记录。 this.context.history.push('/path')

另请参阅对此github问题的回复:https://github.com/ReactTraining/react-router/issues/4059

答案 1 :(得分:9)

所以我来到这个问题,希望得到答案,但无济于事。我用过

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

在同一个项目中,它按预期工作。 经过进一步的实验和一些比较和对比,我意识到如果在嵌套组件中调用此代码将无法运行。因此,只有呈现的页面组件才能调用此函数才能使其正常工作。

查找工作沙箱here

  • 历史:v4.7.2
  • react:v16.0.0
  • react-dom:v16.0.0
  • 反应路由器-DOM: v4.2.2

答案 2 :(得分:5)

您可以尝试使用历史记录加载子组件。这样做,传递历史&#39;通过道具。这样的事情:

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

答案 3 :(得分:3)

我有类似的症状,但是我的问题是我在筑巢BrowserRouter


请勿嵌套BrowserRouter ,因为history对象将引用最近的BrowserRouter父对象。因此,当您执行history.push(targeturl)并且该 targeturl 不在特定的BrowserRouter中时,它将不会与它的任何路由匹配,因此不会加载任何子组件。

解决方案

嵌套Switch而不用BrowserRouter包裹


示例

让我们考虑一下这个App.js文件

<BrowserRouter>
  <Switch>
    <Route exact path="/nestedrouter" component={NestedRouter}  />
    <Route exact path="/target" component={Target}  />
  </Switch>
</BrowserRouter>

而不是在NestedRouter.js文件中这样做

<BrowserRouter>
  <Switch>
    <Route exact path="/nestedrouter/" component={NestedRouter}  />
    <Route exact path="/nestedrouter/subroute" component={SubRoute}  />
  </Switch>
</BrowserRouter>

只需从BrowserRouter文件中删除NestedRouter.js

  <Switch>
    <Route exact path="/nestedrouter/" component={NestedRouter}  />
    <Route exact path="/nestedrouter/subroute" component={SubRoute}  />
  </Switch>

答案 4 :(得分:1)

似乎是一个老问题,但仍然有意义。

我认为这是一个blocked update问题。

主要问题是,新的URL(路由)应该由与当前(当前URL)相同的组件(Costumers)呈现。

解决方案非常简单,将窗口url设置为prop,因此react有机会检测prop的更改(因此url更改),并采取相应的行动。

官方反应博客Recommendation: Fully uncontrolled component with a key中描述了一个很好的用例。

所以解决方案是从 render() { return( <ul>

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

因此,每当位置由react-router更改时,就会废弃该组件(通过react),并使用正确的值(通过react)启动一个新组件。

哦,将location作为属性传递给组件(Costumers),如果尚未传递重定向,它将在该组件上进行重定向。

希望它可以帮助某人。

答案 5 :(得分:1)

对我来说(反应路由器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 :(得分:1)

让我们考虑这种情况。您将App.jsx作为ReactJS SPA的根文件。其中的render()与此类似:

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

然后,您应该可以在this.props.history内使用MyComponent而不会出现问题。假设您正在MySecondComponent内部渲染MyComponent,在这种情况下,您需要以以下方式调用它:

<MySecondComponent {...props} />

会将道具从MyComponent传递到MySecondComponent,从而使this.props.historyMySecondComponent中可用

答案 7 :(得分:0)

不要与路由器一起使用。

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

效果很好。

答案 8 :(得分:0)

您需要导出 Customers 组件而不是 CustomerList

    CustomersList = withRouter(Customers);
    export default CustomersList;

答案 9 :(得分:0)

您可以通过 withRouter 高阶组件访问历史对象的属性和最接近的匹配项。 withRouter 会在渲染时将更新的匹配,位置和历史道具传递给包装的组件。

<div class="loans">
        <h1>Our awesome rates!</h1>
        <div class="loanLenghs">
            <p class="left">30 Year Fixed</p>
            <p class="center">15 Year Fixed</p>
            <p class="right">5/1 ARM</p>
        </div>
        <div class="rates">
            <p class="left">%4.552</p>
            <p class="center">%3.999</p>
            <p class="right">%5.332</p>
        </div>
    </div>

答案 10 :(得分:0)

我看到您正在使用类组件,但如果您决定切换到功能组件或在您的应用程序中遇到与功能组件相同的问题,您可以使用 “useHistory”< /strong> react-router-dom 的钩子 API。

用法示例:

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

const Customers = ({customer}) => {
   let history = useHistory();

   const handleCustomerClick = (customer) => {
     history.push(`/customers/${customer.id}`);
   }

  return (
    //some JSX here
  );
};

您可以在此处找到官方文档:https://reactrouter.com/web/api/Hooks/usehistory

答案 11 :(得分:0)

初学者在处理路由时犯的错误是直接将 withRouter 与组件一起使用,而不是在其间放置任何其他高阶组件(或至少不知道推送 props.history给它的孩子:

错误: export default withRouter(withErrorHandler(Foo));

正确: export default withErrorHandler(withRouter(Foo));

答案 12 :(得分:-3)

您需要绑定try { Runtime rt = Runtime.getRuntime(); rt.exec("cmd /c start cmd.exe /K \"java -version\""); System.out.println("After completing the first command"); rt.exec("cmd /c start cmd.exe /K \"javac -version\""); } catch (Exception e) { System.out.println("Something wrong"); e.printStackTrace(); }

handleCustomerClick

答案 13 :(得分:-3)

BottomAppBar