如何使用 React Router 以编程方式导航?
使用
react-router
,我可以使用
Link
元素创建由 react router 原生处理的链接。
我看到它在内部调用
this.context.transitionTo(...)
。
我想进行导航。不是从链接,而是从下拉选择(作为示例)。我如何在代码中执行此操作?什么是
this.context
?
我看到了
Navigation
mixin,但我可以在没有
mixins
的情况下执行此操作吗?
UPDATE: 2022: React Router v6.6.1 with useNavigate
useHistory()
钩子现已弃用。如果您使用的是 React Router 6,则以编程方式导航的正确方法如下:
import { useNavigate } from "react-router-dom";
function HomeButton() {
const navigate = useNavigate();
function handleClick() {
navigate("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
React Router v5.1.0 with hooks
如果您使用的是 React >16.8.0 和功能组件,则 React Router >5.1.0 中有一个新的
useHistory
钩子。
import { useHistory } from "react-router-dom";
function HomeButton() {
const history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
React Router v4
使用 React Router v4,您可以通过三种方法在组件内进行编程路由。
-
使用
withRouter
高阶组件。 -
使用组合并渲染
<Route>
-
使用
context
。
React Router 主要是
history
库。
history
使用其浏览器和哈希历史记录为您处理与浏览器的
window.history
的交互。它还提供内存历史记录,这对于没有全局历史记录的环境很有用。这在移动应用程序开发(
react-native
)和使用 Node 进行单元测试时特别有用。
history
实例有两种导航方法:
push
和
replace
。如果您将
history
视为访问过位置的数组,则
push
将向数组中添加新位置,而
replace
将用新位置替换数组中的当前位置。通常,您会希望在导航时使用
push
方法。
在 React Router 的早期版本中,您必须创建自己的
history
实例,但在 v4 中,
<BrowserRouter>
、
<HashRouter>
和
<MemoryRouter>
组件将为您创建浏览器、哈希和内存实例。React Router 通过
router
对象下的上下文使与您的路由器关联的
history
实例的属性和方法可用。
1.使用
withRouter
高阶组件
withRouter
高阶组件将注入
history
对象作为组件的 prop。这样您就可以访问
push
和
replace
方法,而无需处理
context
。
import { withRouter } from 'react-router-dom'
// this also works with react-router-native
const Button = withRouter(({ history }) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
))
2. 使用组合并呈现
<Route>
<Route>
组件不仅仅用于匹配位置。您可以呈现无路径路线,并且
它将始终与当前位置匹配
。
<Route>
组件传递与
withRouter
相同的 props,因此您将能够通过
history
prop 访问
history
方法。
import { Route } from 'react-router-dom'
const Button = () => (
<Route render={({ history}) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
)} />
)
3. 使用 context*
但你可能不应该
最后一个选项是仅当你觉得使用 React 的 context 模型 (React 的 Context API 从 v16 开始稳定) 时才应使用的选项。
const Button = (props, context) => (
<button
type='button'
onClick={() => {
// context.history.push === history.push
context.history.push('/new-location')
}}
>
Click Me!
</button>
)
// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired
})
}
1 和 2 是最简单的实现选择,因此对于大多数用例来说,它们是你最好的选择。
React-Router v6+ Answer
TL;DR:
您可以使用新的
useNavigate
钩子。
import { useNavigate } from "react-router-dom";
function Component() {
let navigate = useNavigate();
// Somewhere in your code, e.g. inside a handler:
navigate("/posts");
}
useNavigate
钩子返回一个可用于编程导航的函数。
来自 React Router 文档
import { useNavigate } from "react-router-dom";
function SignupForm() {
let navigate = useNavigate();
async function handleSubmit(event) {
event.preventDefault();
await submitForm(event.target);
navigate("../success", { replace: true });
// replace: true will replace the current entry in
// the history stack instead of adding a new one.
}
return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}
React-Router 5.1.0+ Answer (using hooks and React >16.8)
您可以在功能组件上使用
useHistory
钩子并以编程方式导航:
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
// use history.push('/some/path') here
};
React-Router 4.0.0+ Answer
在 4.0 及更高版本中,使用历史记录作为您的组件。
class Example extends React.Component {
// use `this.props.history.push('/some/path')` here
};
注意:如果您的组件未由
<Route>
呈现,则
this.props.history
不存在。您应该使用
<Route path="..." component={YourComponent}/>
来在 YourComponent 中拥有
this.props.history
。
React-Router 3.0.0+ Answer
在 3.0 及更高版本中,使用路由器作为组件的 prop。
class Example extends React.Component {
// use `this.props.router.push('/some/path')` here
};
React-Router 2.4.0+ Answer
在 2.4 及更高版本中,使用高阶组件将路由器作为组件的 prop。
import { withRouter } from 'react-router';
class Example extends React.Component {
// use `this.props.router.push('/some/path')` here
};
// Export the decorated class
var DecoratedExample = withRouter(Example);
// PropTypes
Example.propTypes = {
router: React.PropTypes.shape({
push: React.PropTypes.func.isRequired
}).isRequired
};
React-Router 2.0.0+ Answer
此版本向后兼容 1.x,因此不需要升级指南。只需浏览示例就足够了。
也就是说,如果您希望切换到新模式,路由器内部有一个
browserHistory
模块,您可以使用它来访问它
import { browserHistory } from 'react-router'
现在您可以访问浏览器历史记录,因此您可以执行推送、替换等操作...例如:
browserHistory.push('/some/path')
进一步阅读: Histories 和 Navigation
React-Router 1.x.x Answer
我不会详细介绍升级细节。您可以在 升级指南
此处问题的主要变化是从
Navigation
mixin 更改为
History
。现在它使用浏览器 historyAPI 来更改路由,因此从现在开始我们将使用
pushState()
。
这是一个使用 Mixin 的示例:
var Example = React.createClass({
mixins: [ History ],
navigateToHelpPage () {
this.history.pushState(null, `/help`);
}
})
请注意,此
History
来自
rackt/history
项目。不是来自 React-Router 本身。
如果您出于某种原因不想使用 Mixin(可能是因为 ES6 类),那么您可以从
this.props.history
访问从路由器获取的历史记录。它只能由您的
Router
呈现的组件访问。因此,如果您想在任何子组件中使用它,则需要通过
props
将其作为属性传递下去。
您可以在他们的 1.0.x 文档 中阅读有关新版本的更多信息。
它建议获取引用
history = createHistory()
并在其上调用
replaceState
。
React-Router 0.13.x Answer
我遇到了同样的问题,只能使用 react-router 附带的 Navigation mixin 找到解决方案。
这是我的做法它
import React from 'react';
import {Navigation} from 'react-router';
let Authentication = React.createClass({
mixins: [Navigation],
handleClick(e) {
e.preventDefault();
this.transitionTo('/');
},
render(){
return (<div onClick={this.handleClick}>Click me!</div>);
}
});
我能够调用
transitionTo()
,而无需访问
.context
或者您可以尝试花哨的 ES6
class
import React from 'react';
export default class Authentication extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
e.preventDefault();
this.context.router.transitionTo('/');
}
render(){
return (<div onClick={this.handleClick}>Click me!</div>);
}
}
Authentication.contextTypes = {
router: React.PropTypes.func.isRequired
};
React-Router-Redux
Note: if you're using Redux, there is another project called React-Router-Redux that gives you redux bindings for ReactRouter, using somewhat the same approach that React-Redux does
React-Router-Redux 有几种可用的方法,允许从动作创建者内部进行简单的导航。这些方法对于那些在 React Native 中已有架构的人来说尤其有用,他们希望在 React Web 中使用相同的模式,同时尽量减少样板开销。
探索以下方法:
-
push(location)
-
replace(location)
-
go(number)
-
goBack()
-
goForward()
以下是使用 Redux-Thunk 的示例:
./actioncreators.js
import { goBack } from 'react-router-redux'
export const onBackPress = () => (dispatch) => dispatch(goBack())
./viewcomponent.js
<button
disabled={submitting}
className="cancel_button"
onClick={(e) => {
e.preventDefault()
this.props.onBackPress()
}}
>
CANCEL
</button>
React-Router v2
对于最新版本 (
v2.0.0-rc5
),建议的导航方法是直接推送到历史单例。您可以在
在组件之外导航文档
中看到实际操作。
相关摘录:
import { browserHistory } from 'react-router';
browserHistory.push('/some/path');
如果使用较新的 react-router API,则需要在组件内部使用
this.props
中的
history
,因此:
this.props.history.push('/some/path');
它还提供
pushState
,但根据记录的警告,该功能已被弃用。
如果使用
react-router-redux
,它会提供一个
push
函数,您可以像这样分派:
import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));
但是,这可能仅用于更改 URL,而不能实际导航到页面。