React-router v4 this.props.history.push(...) 不工作
Posted
技术标签:
【中文标题】React-router v4 this.props.history.push(...) 不工作【英文标题】:React-router v4 this.props.history.push(...) not working 【发布时间】:2017-11-02 21:23:57 【问题描述】:我正在尝试使用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(..),但视图没有更新,客户组件没有呈现,客户列表仍然存在。有什么想法吗?
【问题讨论】:
嗨,我相信真正发生的是两个组件匹配并且两个组件都被渲染。请检查两个组件是否都在执行各自的componentDidMount
?
@FacundoLaRocca 他们在两条路线上都有exact
是的,我知道,但我也遇到过类似的问题。这就是我问的原因。
你可以看看these examples。我猜你必须使用 Switch
组件来匹配你想要的。
@FacundoLaRocca 就像他建议的那样,我认为问题在于两条路线的名称相同,我反驳了同样的问题,只需将客户更改为客户,然后尝试一下
【参考方案1】:
在 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);
【讨论】:
【参考方案2】:初学者在使用路由时的错误是直接将withRouter
与组件一起使用而不在其间放置任何其他高阶组件(或至少一个不知道将props.history
推送给其子级的组件)的重要性:
错误: export default withRouter(withErrorHandler(Foo));
正确: export default withErrorHandler(withRouter(Foo));
【讨论】:
【参考方案3】:我看到您正在使用类组件,但如果您决定切换到功能组件或在应用程序中遇到与功能组件相同的问题,您可以使用 "useHistory" 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
【讨论】:
【参考方案4】:我有类似的症状,但我的问题是我在嵌套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>
只需从 NestedRouter.js
文件中删除 BrowserRouter
<Switch>
<Route exact path="/nestedrouter/" component=NestedRouter />
<Route exact path="/nestedrouter/subroute" component=SubRoute />
</Switch>
【讨论】:
【参考方案5】:让我们考虑一下这种情况。您将 App.jsx
作为 ReactJS SPA 的根文件。在其中您的render()
看起来类似于:
<Switch>
<Route path="/comp" component=MyComponent />
</Switch>
那么,您应该可以在MyComponent
内使用this.props.history
而不会有问题。假设您在MyComponent
中渲染MySecondComponent
,在这种情况下您需要以这种方式调用它:
<MySecondComponent ...props />
这会将道具从MyComponent
传递到MySecondComponent
,从而使this.props.history
在MySecondComponent
中可用
【讨论】:
【参考方案6】:您可以通过 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)
【讨论】:
【参考方案7】:您需要导出 Customers 组件而不是 CustomerList。
CustomersList = withRouter(Customers);
export default CustomersList;
【讨论】:
【参考方案8】:对我来说(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>
【讨论】:
【参考方案9】:似乎是一个老问题,但仍然相关。
我认为这是blocked update 问题。
主要问题是新 URL(路由)应该由与您当前所在的组件(Costumers
)相同的组件(当前 URL)呈现。
所以解决方法比较简单,把window url作为一个prop,这样react就有机会检测到prop的变化(因此就是url的变化),并采取相应的行动。
在名为 Recommendation: Fully uncontrolled component with a key 的官方 react 博客中描述了一个不错的用例。
所以解决方案是从
render()
return(
<ul>
到
render()
return(
<ul key=this.props.location.pathname>
因此,每当 react-router 更改位置时,组件就会被报废(通过 react),并使用正确的值(通过 react)启动一个新组件。
哦,将 location
作为 prop 传递给组件 (Costumers
),如果尚未传递,将在该组件中进行重定向。
希望对某人有所帮助。
【讨论】:
【参考方案10】:所以我来到这个问题希望得到答案,但无济于事。我用过
const history = this.props;
history.push("/thePath")
在同一个项目中,它按预期工作。 经过进一步的实验和一些比较和对比,我意识到这段代码如果在嵌套组件中调用将不会运行。因此只有被渲染的页面组件才能调用该函数才能正常工作。
找到工作沙盒here
历史:v4.7.2 反应:v16.0.0 react-dom: v16.0.0 反应路由器-dom: v4.2.2【讨论】:
鉴于 react-router 的速度有多快,(就此而言,整个 JS 生态系统都在移动),如果你包含你正在使用的版本,它会改善你的答案,如果你的答案会很棒您提供MCVE。像JSFiddle 这样的服务应该会有所帮助。 我得到了 history.push( 不是函数 恕我直言,这与 this.pros.history.pus() 相同。您只需将其放入其他变量中。对我来说都是未定义的......【参考方案11】:this.props.history.push(`/customers/$customer.id`, null);
【讨论】:
欢迎来到 Stack Overflow!如果您可以添加一点解释,说明您为什么认为此调用解决了问题中提出的问题,那就太好了。【参考方案12】:您可以尝试加载具有历史记录的子组件。为此,请通过道具传递“历史”。类似的东西:
return (
<div>
<Login history=this.props.history />
<br/>
<Register/>
</div>
)
【讨论】:
看起来就是这样……而且很伤心【参考方案13】:你需要绑定handleCustomerClick
:
class Customers extends Component
constructor()
super();
this.handleCustomerClick = this.handleCustomerClick(this)
【讨论】:
this.handleCustomerClick = this.handleCustomerClick.bind(this) 为我解决了问题。【参考方案14】:不要与路由器一起使用。
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);
)
效果很好。
【讨论】:
【参考方案15】:在最新版本的 React 路由器中,情况似乎发生了一些变化。您现在可以通过上下文访问历史记录。 this.context.history.push('/path')
另请参阅此 github 问题的回复:https://github.com/ReactTraining/react-router/issues/4059
【讨论】:
更好的方法是使用withRouter
HOC。 github.com/ReactTraining/react-router/blob/master/packages/…以上是关于React-router v4 this.props.history.push(...) 不工作的主要内容,如果未能解决你的问题,请参考以下文章