如何使用React Router进行编程式导航

如何使用React Router进行编程式导航

技术背景

在React应用中,使用React Router来管理路由是常见的做法。有时候,我们需要在代码中进行编程式导航,而不是仅仅依赖于<Link>组件。不同版本的React Router提供了不同的方式来实现编程式导航。

实现步骤

React Router v6及以上

从React Router v6开始,useHistory() 钩子已被弃用,推荐使用 useNavigate 钩子进行编程式导航。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { useNavigate } from "react-router-dom";

function HomeButton() {
const navigate = useNavigate();

function handleClick() {
navigate("/home");
}

return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}

还可以使用 replace 选项来替换当前历史记录条目:

1
2
3
4
5
6
7
8
9
10
11
12
13
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 });
}

return <form onSubmit={handleSubmit}>{/* ... */}</form>;
}

React Router v5.1.0及以上(使用钩子和React >16.8)

可以使用 useHistory 钩子在函数组件中进行编程式导航:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { useHistory } from "react-router-dom";

function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}

return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}

React Router v4

在React Router v4中有三种方法可以在组件内进行编程式路由:

1. 使用 withRouter 高阶组件

withRouter 高阶组件会将 history 对象作为组件的一个属性注入,这样就可以访问 pushreplace 方法:

1
2
3
4
5
6
7
8
9
10
import { withRouter } from 'react-router-dom'

const Button = withRouter(({ history }) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
))

2. 使用组合并渲染 <Route>

可以渲染一个无路径的 <Route>,它将始终匹配当前位置。<Route> 组件传递的属性与 withRouter 相同,因此可以通过 history 属性访问 history 方法:

1
2
3
4
5
6
7
8
9
10
11
12
import { Route } from 'react-router-dom'

const Button = () => (
<Route render={({ history}) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
)} />
)

3. 使用上下文(不推荐)

只有在熟悉React的上下文模型时才使用此方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const Button = (props, context) => (
<button
type='button'
onClick={() => {
context.history.push('/new-location')
}}
>
Click Me!
</button>
)

Button.contextTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired
})
}

React Router v3及以上

在组件中使用 this.props.router.push 进行导航:

1
2
3
4
5
6
7
import { withRouter } from 'react-router';

class Example extends React.Component {
// use `this.props.router.push('/some/path')` here
};

export default withRouter(Example);

React Router v2及以上

可以直接操作 browserHistory 进行导航:

1
2
import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

在组件内,可以使用 this.props.history.push

1
this.props.history.push('/some/path');

React Router v1.x.x

使用 History 混合(Mixin)或通过 this.props.history 访问历史记录:

1
2
3
4
5
6
var Example = React.createClass({
mixins: [ History ],
navigateToHelpPage () {
this.history.pushState(null, `/help`);
}
})

React Router 0.13.x

使用 Navigation 混合(Mixin)或通过上下文访问路由器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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>);
}
});

核心代码

以下是不同版本的核心导航代码示例:

React Router v6

1
2
3
4
5
6
import { useNavigate } from "react-router-dom";

function Component() {
let navigate = useNavigate();
navigate("/posts");
}

React Router v5.1.0

1
2
3
4
5
6
import { useHistory } from "react-router-dom";

function HomeButton() {
let history = useHistory();
history.push("/home");
}

React Router v4

1
2
3
4
5
6
7
8
9
import { withRouter } from 'react-router-dom';

class Home extends Component {
componentDidMount() {
this.props.history.push('/redirect-to');
}
}

export default withRouter(Home);

最佳实践

  • 使用最新版本:尽量使用最新版本的React Router,因为它们通常提供了更简洁和现代的API。
  • 代码复用:将导航逻辑封装在函数或组件中,以便在多个地方复用。
  • 错误处理:在导航时考虑错误处理,例如网络错误或权限问题。

常见问题

  • this.props.history 未定义:确保组件是由 <Route> 渲染的,或者使用 withRouter 高阶组件包裹组件。
  • useHistory 钩子不可用:检查React Router版本是否支持 useHistory 钩子,或者升级到支持的版本。
  • 上下文使用问题:使用上下文时,确保定义了 contextTypes,否则上下文将不可访问。

如何使用React Router进行编程式导航
https://119291.xyz/posts/2025-05-15.how-to-programmatically-navigate-using-react-router/
作者
ww
发布于
2025年5月15日
许可协议