繁体   English   中英

React-router v4 this.props.history.push(...) 不工作

[英]React-router v4 this.props.history.push(...) not working

我正在尝试使用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 仍然存在。 有任何想法吗?

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

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

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

在此处查找工作沙盒

  • 历史:v4.7.2
  • 反应:v16.0.0
  • 反应域:v16.0.0
  • react-router-dom: v4.2.2

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

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

您可以尝试加载具有历史记录的子组件。 为此,请通过道具传递“历史”。 类似的东西:

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

对我来说(react-router v4,react 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>

您可以通过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)

似乎是一个老问题,但仍然相关。

我认为这是一个阻止更新的问题。

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

所以解决办法很简单,把window url作为一个prop,这样react就有机会检测到prop的变化(因此url变化),并采取相应的行动。

官方 React 博客中描述的一个很好的用例,名为“ 推荐:完全不受控制的组件,带有一个键”

所以解决办法是从render() { return( <ul>

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

因此,每当 react-router 更改位置时,组件就会报废(通过反应),并且会以正确的值(通过反应)启动一个新的组件。

哦,并将location作为 prop 传递给组件( Costumers ),如果尚未传递,则会发生重定向。

希望它可以帮助某人。

我有类似的症状,但我的问题是我嵌套了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>

只需删除BrowserRouterNestedRouter.js文件

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

让我们考虑一下这种情况。 你有App.jsx作为你 ReactJS SPA 的根文件。 在其中,您的render()看起来类似于:

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

然后,您应该能够在MyComponent使用this.props.history没有问题。 假设您在MyComponent中呈现MySecondComponent ,在这种情况下,您需要以这种方式调用它:

<MySecondComponent {...props} />

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

您需要导出客户组件而不是CustomerList

    CustomersList = withRouter(Customers);
    export default CustomersList;

我看到您正在使用类组件,但如果您决定切换到功能组件或在应用程序中遇到与功能组件相同的问题,您可以通过react- router使用“useHistory”钩子 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

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

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

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

在 react-router-dom v6 中,对历史的支持已被弃用,但引入了导航。 如果您想在特定事件成功时将用户重定向到特定页面,请按照以下步骤操作:

创建一个名为 withRouter.js 的文件,并将下面给出的代码粘贴到该文件中

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

export const withRouter = (Component) => {
  const Wrapper = (props) => {
    const navigate = useNavigate();

    return (
      <Component
        navigate={navigate}
        {...props}
        />
    );
 };

  return Wrapper;
};

现在,在您想要将用户重定向到特定路径/组件的任何基于类的组件中,在那里导入上面的 withRouter.js 文件并使用 this.props.navigate('/your_path_here') 函数进行重定向。

为了您的帮助,下面给出了显示相同内容的示例代码:

import React from 'react';
import {withRouter} from '.your_Path_To_Withrouter_Here/withRouter';

class Your_Component_Name_Here extends React.Component{
     constructor(){
       super()
       this.yourFunctionHere=this.yourFunctionHere.bind(this);
    }

    yourFunctionHere()
    {
        this.props.navigate('/your_path_here')
    }

    render()
    {
        return(
            <div>
              Your Component Code Here 
            </div>
        )
    }
}

export default withRouter(Your_Component_Name_Here);

我希望它解决了你的问题。 如果它那么赞成这个答案。 谢谢!

不要与路由器一起使用。

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

它运作良好。

您需要绑定handleCustomerClick

class Customers extends Component {
  constructor() {
    super();
    this.handleCustomerClick = this.handleCustomerClick(this)
  }
this.props.history.push(`/customers/${customer.id}`, null);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM