我刚刚把react-router从v3替换为v4。 但我不确定如何以编程方式在组件的成员函数中导航。 即在handleClick()函数中,我想在处理一些数据后导航到/path/some/where。 我以前是这样做的:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
但是我在v4中找不到这样的界面。 如何使用v4导航?
我刚刚把react-router从v3替换为v4。 但我不确定如何以编程方式在组件的成员函数中导航。 即在handleClick()函数中,我想在处理一些数据后导航到/path/some/where。 我以前是这样做的:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
但是我在v4中找不到这样的界面。 如何使用v4导航?
当前回答
我为此纠结了一段时间——如此简单,却又如此复杂,因为ReactJS只是一种完全不同的web应用程序编写方式,这对我们这些老年人来说非常陌生!
我创建了一个单独的组件来抽象混乱:
// LinkButton.js
import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';
export default class LinkButton extends React.Component {
render() {
return (
<Route render={({history}) => (
<button {...this.props}
onClick={() => {
history.push(this.props.to)
}}>
{this.props.children}
</button>
)}/>
);
}
}
LinkButton.propTypes = {
to: PropTypes.string.isRequired
};
然后将它添加到render()方法中:
<LinkButton className="btn btn-primary" to="/location">
Button Text
</LinkButton>
其他回答
由于没有其他方法来处理这个可怕的设计,所以我编写了一个使用withRouter HOC方法的通用组件。下面的例子是包装一个按钮元素,但你可以更改为任何你需要的可点击元素:
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
const NavButton = (props) => (
<Button onClick={() => props.history.push(props.to)}>
{props.children}
</Button>
);
NavButton.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired
}),
to: PropTypes.string.isRequired
};
export default withRouter(NavButton);
用法:
<NavButton to="/somewhere">Click me</NavButton>
我的答案和Alex的相似。我不知道为什么React-Router把这个做得如此复杂。为什么我必须用一个HoC来包装我的组件,只是为了访问本质上是全局的?
不管怎样,如果你看一下他们是如何实现<BrowserRouter>的,它只是一个历史记录的小包装。
我们可以把这段历史提取出来,这样我们就可以从任何地方导入。然而,诀窍在于,如果您正在进行服务器端呈现,并试图导入历史模块,那么它将无法工作,因为它使用的是纯浏览器api。但这没关系,因为我们通常只在响应单击或其他客户端事件时重定向。因此,假装一下是可以的:
// history.js
if(__SERVER__) {
module.exports = {};
} else {
module.exports = require('history').createBrowserHistory();
}
在webpack的帮助下,我们可以定义一些变量,这样我们就知道我们所处的环境:
plugins: [
new DefinePlugin({
'__SERVER__': 'false',
'__BROWSER__': 'true', // you really only need one of these, but I like to have both
}),
现在你可以
import history from './history';
从任何地方。它只会在服务器上返回一个空模块。
如果你不想使用这些神奇的变量,你只需要在需要它的全局对象中(在你的事件处理程序中)。导入不能工作,因为它只在顶层工作。
第一步:只需要在上面导入一个东西:
import {Route} from 'react-router-dom';
第二步:在Route中,传递历史记录:
<Route
exact
path='/posts/add'
render={({history}) => (
<PostAdd history={history} />
)}
/>
第三步:历史被接受为下一个组件的道具的一部分,所以你可以简单地:
this.props.history.push('/');
这很简单,也很有力。
TL; diana:
if (navigate) {
return <Redirect to="/" push={true} />
}
简单和声明性的答案是,您需要结合setState()使用<Redirect to={URL} push={boolean} />
Push:布尔值——当为true时,重定向将把一个新条目推到历史记录中,而不是替换当前的条目。
import { Redirect } from 'react-router'
class FooBar extends React.Component {
state = {
navigate: false
}
render() {
const { navigate } = this.state
// here is the important part
if (navigate) {
return <Redirect to="/" push={true} />
}
// ^^^^^^^^^^^^^^^^^^^^^^^
return (
<div>
<button onClick={() => this.setState({ navigate: true })}>
Home
</button>
</div>
)
}
}
完整的例子。 点击这里阅读更多。
本例使用ES7+属性初始化器初始化状态。如果你感兴趣的话,也看看这里。
我已经测试v4好几天了。到目前为止,我很喜欢它!过一段时间就明白了。
我也有同样的问题,我发现用下面的方法处理它是最好的(甚至可能是它的目的)。它使用state、三元操作符和<Redirect>。
在构造函数()中
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' });
希望能有所帮助。让我知道。