使用 React 路由器以编程方式导航
Programmatically navigate using React router
使用 react-router
我可以使用 Link
元素来创建 links,它们由 React 路由器本地处理。
我看到它在内部调用 this.context.transitionTo(...)
。
我想做导航。不是来自 link,而是来自下拉选择(作为示例)。我怎样才能在代码中做到这一点?什么是 this.context
?
我看到了 Navigation
mixin,但是我可以在没有 mixins
的情况下这样做吗?
React-Router v6+ Answer
您可以使用新的 useNavigate
挂钩。 useNavigate
hook returns 一个可用于编程导航的函数。
来自 React 路由器的示例 documentaion
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 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 及更高版本中,将历史记录用作组件的 prop。
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
升级的细节就不说了。您可以在 Upgrade Guide
中阅读相关内容
此处问题的主要变化是从 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 class),那么你可以从 this.props.history
访问你从路由器获得的历史记录。只有您的路由器呈现的组件才能访问它。所以,如果你想在任何子组件中使用它,它需要通过 props
.
作为属性传递下去
您可以在 1.0.x documentation
阅读更多关于新版本的信息
这里是a help page specifically about navigating outside your component
它建议抓取参考 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>
Warning: this answer covers only ReactRouter versions before 1.0
I will update this answer with 1.0.0-rc1 use cases after!
你也可以不使用 mixin 来做到这一点。
let Authentication = React.createClass({
contextTypes: {
router: React.PropTypes.func
},
handleClick(e) {
e.preventDefault();
this.context.router.transitionTo('/');
},
render(){
return (<div onClick={this.handleClick}>Click me!</div>);
}
});
上下文的问题在于,除非您在 class 上定义 contextTypes
,否则无法访问它。
至于什么是context,就是一个对象,和props一样,从parent传给child,但是是隐式传递的,不用每次都重新声明props。参见 https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html
React-Router v2
对于最新版本 (v2.0.0-rc5
),推荐的导航方法是直接推送到历史单例。您可以在 Navigating outside of Components doc 中看到它的实际效果。
相关摘录:
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,而不是实际导航到页面。
以下是使用 react-router v2.0.0
with ES6 执行此操作的方法。 react-router
已经远离 mixins。
import React from 'react';
export default class MyComponent extends React.Component {
navigateToPage = () => {
this.context.router.push('/my-route')
};
render() {
return (
<button onClick={this.navigateToPage}>Go!</button>
);
}
}
MyComponent.contextTypes = {
router: React.PropTypes.object.isRequired
}
对于这个,谁不控制服务器端,因此使用散列路由器 v2:
将您的 history 放入单独的文件中(例如 app_history.js ES6):
import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });
export default appHistory;
随处使用!
你的反应路由器入口点(app.js ES6):
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
<Router history={appHistory}>
...
</Router>
), document.querySelector('[data-role="app"]'));
您在任何组件 (ES6) 中的导航:
import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
if (err) {
console.error(err); // login failed
} else {
// logged in
appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
}
})
对于 ES6 + React 组件,以下解决方案对我有用。
我关注了 Felippe skinner,但添加了一个端到端的解决方案来帮助像我这样的初学者。
以下是我使用的版本:
"react-router": "^2.7.0"
"react": "^15.3.1"
下面是我的反应组件,我在其中使用反应路由器进行编程导航:
import React from 'react';
class loginComp extends React.Component {
constructor( context) {
super(context);
this.state = {
uname: '',
pwd: ''
};
}
redirectToMainPage(){
this.context.router.replace('/home');
}
render(){
return <div>
// skipping html code
<button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
</div>;
}
};
loginComp.contextTypes = {
router: React.PropTypes.object.isRequired
}
module.exports = loginComp;
下面是我的路由器的配置:
import { Router, Route, IndexRedirect, browserHistory } from 'react-router'
render(<Router history={browserHistory}>
<Route path='/' component={ParentComp}>
<IndexRedirect to = "/login"/>
<Route path='/login' component={LoginComp}/>
<Route path='/home' component={HomeComp}/>
<Route path='/repair' component={RepairJobComp} />
<Route path='/service' component={ServiceJobComp} />
</Route>
</Router>, document.getElementById('root'));
随着 React-Router v4 的出现,现在有一种新的方法可以做到这一点。
import { MemoryRouter, BrowserRouter } from 'react-router';
const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;
<Router location="/page-to-go-to"/>
react-lego is an example app that shows how to use/update react-router 并且它包含导航应用程序的示例功能测试。
这可能不是最好的方法,但是...使用 react-router v4,以下 TypeScript 代码可以为某些人提供一个想法。
在下面的渲染组件中,例如LoginPage
、router
对象可访问,只需调用 router.transitionTo('/homepage')
即可导航。
导航码被占用from。
"react-router": "^4.0.0-2",
"react": "^15.3.1",
import Router from 'react-router/BrowserRouter';
import { History } from 'react-history/BrowserHistory';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
interface MatchWithPropsInterface {
component: typeof React.Component,
router: Router,
history: History,
exactly?: any,
pattern: string
}
class MatchWithProps extends React.Component<MatchWithPropsInterface,any> {
render() {
return(
<Match {...this.props} render={(matchProps) => (
React.createElement(this.props.component, this.props)
)}
/>
)
}
}
ReactDOM.render(
<Router>
{({ router }) => (
<div>
<MatchWithProps exactly pattern="/" component={LoginPage} router={router} history={history} />
<MatchWithProps pattern="/login" component={LoginPage} router={router} history={history} />
<MatchWithProps pattern="/homepage" component={HomePage} router={router} history={history} />
<Miss component={NotFoundView} />
</div>
)}
</Router>,
document.getElementById('app')
);
对于当前的 React 版本 (15.3),this.props.history.push('/location');
对我有用,但它显示了以下警告:
browser.js:49 Warning: [react-router] props.history
and
context.history
are deprecated. Please use context.router
.
我用 context.router
解决了这个问题:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.backPressed = this.backPressed.bind(this);
}
backPressed() {
this.context.router.push('/back-location');
}
...
}
MyComponent.contextTypes = {
router: React.PropTypes.object.isRequired
};
export default MyComponent;
React-Router V4
如果您使用的是版本 4,那么您可以使用我的库(shameless 插件),您只需发送一个动作,一切正常!
dispatch(navigateTo("/aboutUs"));
这是最简单和最干净的方法,大约当前的 React-Router 3.0.0 和 ES6:
React-Router 3.x.x with ES6:
import { withRouter } from 'react-router';
class Example extends React.Component {
// use `this.props.router.push('/some/path')` here
};
// Export the decorated class
export default withRouter(Example);
或者,如果它不是您的默认设置 class,则导出为:
withRouter(Example);
export { Example };
请注意,在 3.x.x 中,<Link>
组件本身正在使用 router.push
,因此您可以将任何要传递给 <Link to=
标记的内容传递给它,例如:
this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'
基于之前的 :
新奇?将用 TypeScript 编写并使用 decorators
或一个静态property/field
import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";
export interface INavigatorProps {
router?: ReactRouter.History.History;
}
/**
* Note: goes great with mobx
* @inject("something") @withRouter @observer
*/
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
navigate: (to: string) => void;
constructor(props: INavigatorProps) {
super(props);
let self = this;
this.navigate = (to) => self.props.router.push(to);
}
render() {
return (
<ul>
<li onClick={() => this.navigate("/home")}>
Home
</li>
<li onClick={() => this.navigate("/about")}>
About
</li>
</ul>
)
}
}
/**
* Non decorated
*/
export class Navigator2 extends Component<INavigatorProps, {}> {
static contextTypes = {
router: React.PropTypes.object.isRequired,
};
navigate: (to: string) => void;
constructor(props: INavigatorProps, context: any) {
super(props, context);
let s = this;
this.navigate = (to) =>
s.context.router.push(to);
}
render() {
return (
<ul>
<li onClick={() => this.navigate("/home")}>
Home
</li>
<li onClick={() => this.navigate("/about")}>
About
</li>
</ul>
)
}
}
今天安装的任何 npm。
“反应路由器”:“^3.0.0”和
"@types/react-router": "^2.0.41"
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
higher-order 组件。
- 使用合成并渲染
<Route>
- 使用
context
.
React Router 主要是 history
library. history
handles interaction with the browser's window.history
的包装器,带有浏览器和哈希历史记录。它还提供了一个内存历史,这对于没有全局历史的环境很有用。这在移动应用程序开发 (react-native
) 和 Node 单元测试中特别有用。
一个history
实例有两种导航方法:push
和replace
。如果您将 history
视为访问位置的数组,push
将向数组添加一个新位置,而 replace
将用新位置替换数组中的当前位置。通常,您会希望在导航时使用 push
方法。
在早期版本的 React Router 中,您必须创建自己的 history
实例,但在 v4 中,<BrowserRouter>
、<HashRouter>
和 <MemoryRouter>
组件将创建为您提供浏览器、哈希和内存实例。 React Router 使与你的路由器关联的 history
实例的属性和方法可通过 router
对象下的上下文获得。
1。使用 withRouter
higher-order 组件
withRouter
higher-order 组件将注入 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
相同的属性,因此您将能够通过 history
属性访问 history
方法。
import { Route } from 'react-router-dom'
const Button = () => (
<Route render={({ history}) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
)} />
)
3。使用上下文*
但你可能不应该
最后一个选项只有在您对 React 的 context 模型感到满意时才应该使用(React 的上下文 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 是最容易实施的选择,因此对于大多数用例而言,它们是您的最佳选择。
要以编程方式进行导航,您需要将新的 历史记录 推送到 [=11] 中的 props.history =],所以像这样的东西可以为你完成工作:
//using ES6
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick(e) {
e.preventDefault()
/* Look at here, you can add it here */
this.props.history.push('/redirected');
}
render() {
return (
<div>
<button onClick={this.handleClick}>
Redirect!!!
</button>
</div>
)
}
}
export default App;
React-Router 4.x 回答
在我这边,我喜欢有一个历史对象,我什至可以携带外部组件。我喜欢按需导入单个 history.js 文件,然后对其进行操作。
您只需将 BrowserRouter
更改为 Router,并指定 history prop。这不会为您带来任何改变,除了您拥有自己的历史对象,您可以随意操作它。
您需要安装 history,react-router
使用的库。
用法示例,ES6 表示法:
history.js
import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()
BasicComponent.js
import React, { Component } from 'react';
import history from './history';
class BasicComponent extends Component {
goToIndex(e){
e.preventDefault();
history.push('/');
}
render(){
return <a href="#" onClick={this.goToIndex}>Previous</a>;
}
}
如果您必须从实际从 Route
组件呈现的组件导航,您还可以从 props 访问历史记录,例如:
BasicComponent.js
import React, { Component } from 'react';
class BasicComponent extends Component {
navigate(e){
e.preventDefault();
this.props.history.push('/url');
}
render(){
return <a href="#" onClick={this.navigate}>Previous</a>;
}
}
如果您使用哈希或浏览器历史记录,那么您可以
hashHistory.push('/login');
browserHistory.push('/login');
In React-Router v4 and ES6
您可以使用 withRouter
和 this.props.history.push
。
import {withRouter} from 'react-router-dom';
class Home extends Component {
componentDidMount() {
this.props.history.push('/redirect-to');
}
}
export default withRouter(Home);
只需使用this.props.history.push('/where/to/go');
反应路由器 v6
我有一段时间没有接触 React,但要感谢并强调 :
on React-Router 6.0 <Redirect /> changed to <Navigate />
React Router V4
tl:dr;
if (navigate) {
return <Redirect to="/" push={true} />
}
简单而明确的答案是您需要将 <Redirect to={URL} push={boolean} />
与 setState()
结合使用
push: boolean - when true, redirecting will push a new entry onto the history instead of replacing the current one.
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>
)
}
}
PS。如果您有兴趣,该示例也使用 ES7+ Property Initializers to initialise state. Look here。
也许不是最好的解决方案,但它完成了工作:
import { Link } from 'react-router-dom';
// Create functional component Post
export default Post = () => (
<div className="component post">
<button className="button delete-post" onClick={() => {
// ... delete post
// then redirect, without page reload, by triggering a hidden Link
document.querySelector('.trigger.go-home').click();
}}>Delete Post</button>
<Link to="/" className="trigger go-home hidden"></Link>
</div>
);
基本上,与一个操作相关的逻辑(在本例中为 post 删除)最终会调用重定向触发器。这并不理想,因为您将向您的标记添加一个 DOM 节点 'trigger',以便您可以在需要时方便地调用它。此外,您将直接与 DOM 交互,这在 React 组件中可能是不需要的。
不过,这种重定向并不经常需要。因此,组件标记中的一两个额外的隐藏链接不会造成太大伤害,尤其是如果您为它们指定有意义的名称。
在撰写本文时,正确答案对我而言
this.context.router.history.push('/');
但是你需要在你的组件中添加 PropTypes
Header.contextTypes = {
router: PropTypes.object.isRequired
}
export default Header;
别忘了导入 PropTypes
import PropTypes from 'prop-types';
如果您碰巧通过 react-router-redux 将 RR4 与 redux 配对,也可以选择使用 react-router-redux
中的路由操作创建器。
import { push, replace, ... } from 'react-router-redux'
class WrappedComponent extends React.Component {
handleRedirect(url, replaceState = true) {
replaceState
? this.props.dispatch(replace(url))
: this.props.dispatch(push(url))
}
render() { ... }
}
export default connect(null)(WrappedComponent)
如果您使用 redux thunk/saga 来管理异步流程,在 redux 操作中导入上述操作创建器并使用 mapDispatchToProps 挂钩到 React 组件可能会更好。
要将 withRouter
与基于 class 的组件一起使用,请尝试以下操作。
不要忘记将导出语句更改为使用 withRouter
:
import { withRouter } from 'react-router-dom'
class YourClass extends React.Component {
yourFunction = () => {
doSomeAsyncAction(() =>
this.props.history.push('/other_location')
)
}
render() {
return (
<div>
<Form onSubmit={ this.yourFunction } />
</div>
)
}
}
export default withRouter(YourClass);
在 React Router v4 中,我遵循这两种方式以编程方式进行路由。
this.props.history.push("/something/something")
this.props.history.replace("/something/something")
第二名
Replaces the current entry on the history stack
要在 props 中获取历史记录,您可能需要用
包装您的组件
在 React Router v6 中
import { useNavigate } from "react-router-dom";
function Invoices() {
let navigate = useNavigate();
return (
<div>
<NewInvoiceForm
onSubmit={async event => {
let newInvoice = await createInvoice(event.target);
navigate(`/invoices/${newInvoice.id}`);
}}
/>
</div>
);
}
那些在 React Router v4 中实现它时遇到问题的人。
这是一个从 redux 操作中浏览 React 应用程序的有效解决方案。
文件history.js
import createHistory from 'history/createBrowserHistory'
export default createHistory()
文件 App.js/Route.jsx
import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
<Route path="/test" component={Test}/>
</Router>
文件*another_file.js或redux文件
import history from './history'
history.push('/test') // This should change the URL and rerender Test component
感谢 GitHub 上的这条评论:
ReactTraining issues comment
React Router v4+
假设您在初始渲染过程中不需要导航(您可以使用 <Redirect>
组件),这就是我们在应用程序中所做的。
定义一个空路由,returns null。这将允许您访问历史对象。您需要在定义 Router
的顶层执行此操作。
现在您可以做在 history 上可以做的所有事情,例如 history.push()
、history.replace()
、history.go(-1)
等!
import React from 'react';
import { HashRouter, Route } from 'react-router-dom';
let routeHistory = null;
export function navigateTo(path) {
if(routeHistory !== null) {
routeHistory.push(path);
}
}
export default function App(props) {
return (
<HashRouter hashType="noslash">
<Route
render={({ history }) => {
routeHistory = history;
return null;
}}
/>
{/* Rest of the App */}
</HashRouter>
);
}
这对我有用,不需要特殊导入:
<input
type="button"
name="back"
id="back"
class="btn btn-primary"
value="Back"
onClick={() => { this.props.history.goBack() }}
/>
您还可以在无状态组件中使用 useHistory
挂钩。文档中的示例:
import { useHistory } from "react-router"
function HomeButton() {
const history = useHistory()
return (
<button type="button" onClick={() => history.push("/home")}>
Go home
</button>
)
}
Note: Hooks were added in react-router@5.1.0
and require react@>=16.8
在我的回答中,有三种不同的方法可以以编程方式重定向到路由。已经介绍了一些解决方案,但以下解决方案仅针对 功能组件 以及附加的演示应用程序。
使用以下版本:
react: 16.13.1
react-dom: 16.13.1
react-router: 5.2.0
react-router-dom: 5.2.0
typescript: 3.7.2
配置:
所以首先解决方案是使用HashRouter
,配置如下:
<HashRouter>
// ... buttons for redirect
<Switch>
<Route exact path="/(|home)" children={Home} />
<Route exact path="/usehistory" children={UseHistoryResult} />
<Route exact path="/withrouter" children={WithRouterResult} />
<Route exact path="/redirectpush" children={RedirectPushResult} />
<Route children={Home} />
</Switch>
</HashRouter>
来自 the documentation 关于 <HashRouter>
:
A <Router>
that uses the hash portion of the URL (i.e. window.location.hash
) to keep your UI in sync with the URL.
解法:
- 使用
<Redirect>
推送使用useState
:
在功能组件中使用(RedirectPushAction
component from my repository) we can use useState
来处理重定向。棘手的部分是一旦重定向发生,我们需要将 redirect
状态设置回 false
。通过使用setTimeOut
延迟 0
我们正在等待 React 将 Redirect
提交给 DOM 然后取回按钮以便下次使用它。
请在下面找到我的示例:
const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
let render = null;
if (redirect) {
render = <Redirect to="/redirectpush" push={true} />
// In order wait until committing to the DOM
// and get back the button for clicking next time
setTimeout(() => setRedirect(false), 0);
}
return render;
}, [redirect]);
return <>
{handleRedirect()}
<button onClick={() => setRedirect(true)}>
Redirect push
</button>
</>
来自 <Redirect>
文档:
Rendering a <Redirect>
will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.
- 使用
useHistory
钩子:
在我的解决方案中有一个名为 UseHistoryAction
的组件,它表示以下内容:
let history = useHistory();
return <button onClick={() => { history.push('/usehistory') }}>
useHistory redirect
</button>
The useHistory
hook gives us access to the history object which helps us programmatically navigate or change routes.
- 使用
withRouter
,从props
得到history
:
创建了一个名为WithRouterAction
的组件,显示如下:
const WithRouterAction = (props:any) => {
const { history } = props;
return <button onClick={() => { history.push('/withrouter') }}>
withRouter redirect
</button>
}
export default withRouter(WithRouterAction);
正在阅读 withRouter
文档:
You can get access to the history
object's properties and the closest <Route>
's match via the withRouter
higher-order component. withRouter
will pass updated match
, location
, and history
props to the wrapped component whenever it renders.
演示:
为了更好地展示我已经用这些示例构建了一个 GitHub 存储库,请在下面找到它:
react-router-dom: 5.1.2
本网站有 3 个页面,所有页面均在浏览器中动态呈现。
虽然页面永远不会刷新,但请注意 React Router 如何
在您浏览网站时使 URL 保持最新。这个
保留浏览器历史记录,确保像后面这样的事情
按钮和书签正常工作
A Switch 遍历所有子节点
元素并呈现第一个其路径
匹配当前 URL。随时使用
你有多条路线,但你只想要一条
其中一次渲染
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
</Router>
);
}
// You can think of these components as "pages"
// in your app.
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}```
试试 React Hook Router,“react-router 的现代替代品”:
import { useRoutes, usePath, A} from "hookrouter";
要回答 OP 关于通过 select 框链接的问题,您可以这样做:
navigate('/about');
更新答案
我认为 React Hook Router 是一个很好的入门工具包,帮助我学习了路由,但我已经更新到 React Router 以了解其历史记录和查询参数处理。
import { useLocation, useHistory } from 'react-router-dom';
const Component = (props) => {
const history = useHistory();
// Programmatically navigate
history.push(newUrlString);
}
您将要导航的位置推入 location.history。
带有钩子的 React Router v6
import {useNavigate} from 'react-router-dom';
let navigate = useNavigate();
navigate('home');
并浏览浏览器历史记录,
navigate(-1); ---> Go back
navigate(1); ---> Go forward
navigate(-2); ---> Move two steps backward.
以编程方式在 class-based 个组件中导航。
import { Redirect } from "react-router-dom";
class MyComponent extends React.Component{
state = {rpath: null}
const goTo = (path) => this.setState({rpath: path});
render(){
if(this.state.rpath){
return <Redirect to={this.state.rpath}/>
}
.....
.....
}
}
如果您使用的是较新版本的 React,使用“useHistory”挂钩是最佳选择。
这已经提到我们可以使用 useNavigate()
在上次更新的 React Router V6(不包括 useHistory
)中导航
import { useNavigate } from 'react-router-dom';
const myComponent = () => {
const navigate = useNavigate();
navigate('my_url');
...
}
但我在这里找不到的是调用导航出 React 组件,例如在 redux-saga
函数内导航页面到另一个页面。以防万一,如果你有同样的问题,这是我找到的。
在你的根组件中(我称之为 <App />
)
import { useNavigate } from 'react-router-dom';
import useBus from 'use-bus';
const App = () => {
const navigate = useNavigate();
useBus('@@ui/navigate', (action) => navigate(action.payload.url), []);
...
}
没有 React 组件(在我的例子中是 redux-saga
函数)
import { dispatch } from 'use-bus';
dispatch({ type: '@@ui/navigate', payload: { url: '/404' } });
希望对您有所帮助!
对于已经在使用 React Router v6 的用户,可以使用 react-router
提供的 useNavigate
钩子来完成。
使用这个钩子导航非常简单:
import { generatePath, useNavigate } from 'react-router';
navigate(-1); // navigates back
navigate('/my/path'); // navigates to a specific path
navigate(generatePath('my/path/:id', { id: 1 })); // navigates to a dynamic path, generatePath is very useful for url replacements
最新 react-router-dom v6
useHistory()
替换为 useNavigate()
。
您需要使用:
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
navigate('/your-page-link');
为了简单起见,只需使用 useNavigate
最新版本的 react
Newfile.js
import { useNavigate } from "react-router-dom";
const Newfile = () => {
const navigate = useNavigate();
....
navigate("yourdesiredlocation");
....
}
export default Newfile;
在您的代码中使用上述 useNavigate
功能。
使用 react-router
我可以使用 Link
元素来创建 links,它们由 React 路由器本地处理。
我看到它在内部调用 this.context.transitionTo(...)
。
我想做导航。不是来自 link,而是来自下拉选择(作为示例)。我怎样才能在代码中做到这一点?什么是 this.context
?
我看到了 Navigation
mixin,但是我可以在没有 mixins
的情况下这样做吗?
React-Router v6+ Answer
您可以使用新的 useNavigate
挂钩。 useNavigate
hook returns 一个可用于编程导航的函数。
来自 React 路由器的示例 documentaion
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 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 及更高版本中,将历史记录用作组件的 prop。
class Example extends React.Component {
// use `this.props.history.push('/some/path')` here
};
注意:如果您的组件不是由 <Route>
呈现的,则 this.props.history 不存在。您应该使用 <Route path="..." component={YourComponent}/>
在 YourComponent
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
升级的细节就不说了。您可以在 Upgrade Guide
中阅读相关内容此处问题的主要变化是从 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 class),那么你可以从 this.props.history
访问你从路由器获得的历史记录。只有您的路由器呈现的组件才能访问它。所以,如果你想在任何子组件中使用它,它需要通过 props
.
您可以在 1.0.x documentation
阅读更多关于新版本的信息这里是a help page specifically about navigating outside your component
它建议抓取参考 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>
Warning: this answer covers only ReactRouter versions before 1.0
I will update this answer with 1.0.0-rc1 use cases after!
你也可以不使用 mixin 来做到这一点。
let Authentication = React.createClass({
contextTypes: {
router: React.PropTypes.func
},
handleClick(e) {
e.preventDefault();
this.context.router.transitionTo('/');
},
render(){
return (<div onClick={this.handleClick}>Click me!</div>);
}
});
上下文的问题在于,除非您在 class 上定义 contextTypes
,否则无法访问它。
至于什么是context,就是一个对象,和props一样,从parent传给child,但是是隐式传递的,不用每次都重新声明props。参见 https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html
React-Router v2
对于最新版本 (v2.0.0-rc5
),推荐的导航方法是直接推送到历史单例。您可以在 Navigating outside of Components doc 中看到它的实际效果。
相关摘录:
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,而不是实际导航到页面。
以下是使用 react-router v2.0.0
with ES6 执行此操作的方法。 react-router
已经远离 mixins。
import React from 'react';
export default class MyComponent extends React.Component {
navigateToPage = () => {
this.context.router.push('/my-route')
};
render() {
return (
<button onClick={this.navigateToPage}>Go!</button>
);
}
}
MyComponent.contextTypes = {
router: React.PropTypes.object.isRequired
}
对于这个,谁不控制服务器端,因此使用散列路由器 v2:
将您的 history 放入单独的文件中(例如 app_history.js ES6):
import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });
export default appHistory;
随处使用!
你的反应路由器入口点(app.js ES6):
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
<Router history={appHistory}>
...
</Router>
), document.querySelector('[data-role="app"]'));
您在任何组件 (ES6) 中的导航:
import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
if (err) {
console.error(err); // login failed
} else {
// logged in
appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
}
})
对于 ES6 + React 组件,以下解决方案对我有用。
我关注了 Felippe skinner,但添加了一个端到端的解决方案来帮助像我这样的初学者。
以下是我使用的版本:
"react-router": "^2.7.0"
"react": "^15.3.1"
下面是我的反应组件,我在其中使用反应路由器进行编程导航:
import React from 'react';
class loginComp extends React.Component {
constructor( context) {
super(context);
this.state = {
uname: '',
pwd: ''
};
}
redirectToMainPage(){
this.context.router.replace('/home');
}
render(){
return <div>
// skipping html code
<button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
</div>;
}
};
loginComp.contextTypes = {
router: React.PropTypes.object.isRequired
}
module.exports = loginComp;
下面是我的路由器的配置:
import { Router, Route, IndexRedirect, browserHistory } from 'react-router'
render(<Router history={browserHistory}>
<Route path='/' component={ParentComp}>
<IndexRedirect to = "/login"/>
<Route path='/login' component={LoginComp}/>
<Route path='/home' component={HomeComp}/>
<Route path='/repair' component={RepairJobComp} />
<Route path='/service' component={ServiceJobComp} />
</Route>
</Router>, document.getElementById('root'));
随着 React-Router v4 的出现,现在有一种新的方法可以做到这一点。
import { MemoryRouter, BrowserRouter } from 'react-router';
const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;
<Router location="/page-to-go-to"/>
react-lego is an example app that shows how to use/update react-router 并且它包含导航应用程序的示例功能测试。
这可能不是最好的方法,但是...使用 react-router v4,以下 TypeScript 代码可以为某些人提供一个想法。
在下面的渲染组件中,例如LoginPage
、router
对象可访问,只需调用 router.transitionTo('/homepage')
即可导航。
导航码被占用from。
"react-router": "^4.0.0-2",
"react": "^15.3.1",
import Router from 'react-router/BrowserRouter';
import { History } from 'react-history/BrowserHistory';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();
interface MatchWithPropsInterface {
component: typeof React.Component,
router: Router,
history: History,
exactly?: any,
pattern: string
}
class MatchWithProps extends React.Component<MatchWithPropsInterface,any> {
render() {
return(
<Match {...this.props} render={(matchProps) => (
React.createElement(this.props.component, this.props)
)}
/>
)
}
}
ReactDOM.render(
<Router>
{({ router }) => (
<div>
<MatchWithProps exactly pattern="/" component={LoginPage} router={router} history={history} />
<MatchWithProps pattern="/login" component={LoginPage} router={router} history={history} />
<MatchWithProps pattern="/homepage" component={HomePage} router={router} history={history} />
<Miss component={NotFoundView} />
</div>
)}
</Router>,
document.getElementById('app')
);
对于当前的 React 版本 (15.3),this.props.history.push('/location');
对我有用,但它显示了以下警告:
browser.js:49 Warning: [react-router]
props.history
andcontext.history
are deprecated. Please usecontext.router
.
我用 context.router
解决了这个问题:
import React from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.backPressed = this.backPressed.bind(this);
}
backPressed() {
this.context.router.push('/back-location');
}
...
}
MyComponent.contextTypes = {
router: React.PropTypes.object.isRequired
};
export default MyComponent;
React-Router V4
如果您使用的是版本 4,那么您可以使用我的库(shameless 插件),您只需发送一个动作,一切正常!
dispatch(navigateTo("/aboutUs"));
这是最简单和最干净的方法,大约当前的 React-Router 3.0.0 和 ES6:
React-Router 3.x.x with ES6:
import { withRouter } from 'react-router';
class Example extends React.Component {
// use `this.props.router.push('/some/path')` here
};
// Export the decorated class
export default withRouter(Example);
或者,如果它不是您的默认设置 class,则导出为:
withRouter(Example);
export { Example };
请注意,在 3.x.x 中,<Link>
组件本身正在使用 router.push
,因此您可以将任何要传递给 <Link to=
标记的内容传递给它,例如:
this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'
基于之前的
新奇?将用 TypeScript 编写并使用 decorators 或一个静态property/field
import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";
export interface INavigatorProps {
router?: ReactRouter.History.History;
}
/**
* Note: goes great with mobx
* @inject("something") @withRouter @observer
*/
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
navigate: (to: string) => void;
constructor(props: INavigatorProps) {
super(props);
let self = this;
this.navigate = (to) => self.props.router.push(to);
}
render() {
return (
<ul>
<li onClick={() => this.navigate("/home")}>
Home
</li>
<li onClick={() => this.navigate("/about")}>
About
</li>
</ul>
)
}
}
/**
* Non decorated
*/
export class Navigator2 extends Component<INavigatorProps, {}> {
static contextTypes = {
router: React.PropTypes.object.isRequired,
};
navigate: (to: string) => void;
constructor(props: INavigatorProps, context: any) {
super(props, context);
let s = this;
this.navigate = (to) =>
s.context.router.push(to);
}
render() {
return (
<ul>
<li onClick={() => this.navigate("/home")}>
Home
</li>
<li onClick={() => this.navigate("/about")}>
About
</li>
</ul>
)
}
}
今天安装的任何 npm。
“反应路由器”:“^3.0.0”和
"@types/react-router": "^2.0.41"
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
higher-order 组件。 - 使用合成并渲染
<Route>
- 使用
context
.
React Router 主要是 history
library. history
handles interaction with the browser's window.history
的包装器,带有浏览器和哈希历史记录。它还提供了一个内存历史,这对于没有全局历史的环境很有用。这在移动应用程序开发 (react-native
) 和 Node 单元测试中特别有用。
一个history
实例有两种导航方法:push
和replace
。如果您将 history
视为访问位置的数组,push
将向数组添加一个新位置,而 replace
将用新位置替换数组中的当前位置。通常,您会希望在导航时使用 push
方法。
在早期版本的 React Router 中,您必须创建自己的 history
实例,但在 v4 中,<BrowserRouter>
、<HashRouter>
和 <MemoryRouter>
组件将创建为您提供浏览器、哈希和内存实例。 React Router 使与你的路由器关联的 history
实例的属性和方法可通过 router
对象下的上下文获得。
1。使用 withRouter
higher-order 组件
withRouter
higher-order 组件将注入 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
相同的属性,因此您将能够通过 history
属性访问 history
方法。
import { Route } from 'react-router-dom'
const Button = () => (
<Route render={({ history}) => (
<button
type='button'
onClick={() => { history.push('/new-location') }}
>
Click Me!
</button>
)} />
)
3。使用上下文*
但你可能不应该
最后一个选项只有在您对 React 的 context 模型感到满意时才应该使用(React 的上下文 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 是最容易实施的选择,因此对于大多数用例而言,它们是您的最佳选择。
要以编程方式进行导航,您需要将新的 历史记录 推送到 [=11] 中的 props.history =],所以像这样的东西可以为你完成工作:
//using ES6
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick(e) {
e.preventDefault()
/* Look at here, you can add it here */
this.props.history.push('/redirected');
}
render() {
return (
<div>
<button onClick={this.handleClick}>
Redirect!!!
</button>
</div>
)
}
}
export default App;
React-Router 4.x 回答
在我这边,我喜欢有一个历史对象,我什至可以携带外部组件。我喜欢按需导入单个 history.js 文件,然后对其进行操作。
您只需将 BrowserRouter
更改为 Router,并指定 history prop。这不会为您带来任何改变,除了您拥有自己的历史对象,您可以随意操作它。
您需要安装 history,react-router
使用的库。
用法示例,ES6 表示法:
history.js
import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()
BasicComponent.js
import React, { Component } from 'react';
import history from './history';
class BasicComponent extends Component {
goToIndex(e){
e.preventDefault();
history.push('/');
}
render(){
return <a href="#" onClick={this.goToIndex}>Previous</a>;
}
}
如果您必须从实际从 Route
组件呈现的组件导航,您还可以从 props 访问历史记录,例如:
BasicComponent.js
import React, { Component } from 'react';
class BasicComponent extends Component {
navigate(e){
e.preventDefault();
this.props.history.push('/url');
}
render(){
return <a href="#" onClick={this.navigate}>Previous</a>;
}
}
如果您使用哈希或浏览器历史记录,那么您可以
hashHistory.push('/login');
browserHistory.push('/login');
In React-Router v4 and ES6
您可以使用 withRouter
和 this.props.history.push
。
import {withRouter} from 'react-router-dom';
class Home extends Component {
componentDidMount() {
this.props.history.push('/redirect-to');
}
}
export default withRouter(Home);
只需使用this.props.history.push('/where/to/go');
反应路由器 v6
我有一段时间没有接触 React,但要感谢并强调
on React-Router 6.0 <Redirect /> changed to <Navigate />
React Router V4
tl:dr;
if (navigate) {
return <Redirect to="/" push={true} />
}
简单而明确的答案是您需要将 <Redirect to={URL} push={boolean} />
与 setState()
push: boolean - when true, redirecting will push a new entry onto the history instead of replacing the current one.
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>
)
}
}
PS。如果您有兴趣,该示例也使用 ES7+ Property Initializers to initialise state. Look here。
也许不是最好的解决方案,但它完成了工作:
import { Link } from 'react-router-dom';
// Create functional component Post
export default Post = () => (
<div className="component post">
<button className="button delete-post" onClick={() => {
// ... delete post
// then redirect, without page reload, by triggering a hidden Link
document.querySelector('.trigger.go-home').click();
}}>Delete Post</button>
<Link to="/" className="trigger go-home hidden"></Link>
</div>
);
基本上,与一个操作相关的逻辑(在本例中为 post 删除)最终会调用重定向触发器。这并不理想,因为您将向您的标记添加一个 DOM 节点 'trigger',以便您可以在需要时方便地调用它。此外,您将直接与 DOM 交互,这在 React 组件中可能是不需要的。
不过,这种重定向并不经常需要。因此,组件标记中的一两个额外的隐藏链接不会造成太大伤害,尤其是如果您为它们指定有意义的名称。
在撰写本文时,正确答案对我而言
this.context.router.history.push('/');
但是你需要在你的组件中添加 PropTypes
Header.contextTypes = {
router: PropTypes.object.isRequired
}
export default Header;
别忘了导入 PropTypes
import PropTypes from 'prop-types';
如果您碰巧通过 react-router-redux 将 RR4 与 redux 配对,也可以选择使用 react-router-redux
中的路由操作创建器。
import { push, replace, ... } from 'react-router-redux'
class WrappedComponent extends React.Component {
handleRedirect(url, replaceState = true) {
replaceState
? this.props.dispatch(replace(url))
: this.props.dispatch(push(url))
}
render() { ... }
}
export default connect(null)(WrappedComponent)
如果您使用 redux thunk/saga 来管理异步流程,在 redux 操作中导入上述操作创建器并使用 mapDispatchToProps 挂钩到 React 组件可能会更好。
要将 withRouter
与基于 class 的组件一起使用,请尝试以下操作。
不要忘记将导出语句更改为使用 withRouter
:
import { withRouter } from 'react-router-dom'
class YourClass extends React.Component {
yourFunction = () => {
doSomeAsyncAction(() =>
this.props.history.push('/other_location')
)
}
render() {
return (
<div>
<Form onSubmit={ this.yourFunction } />
</div>
)
}
}
export default withRouter(YourClass);
在 React Router v4 中,我遵循这两种方式以编程方式进行路由。
this.props.history.push("/something/something")
this.props.history.replace("/something/something")
第二名
Replaces the current entry on the history stack
要在 props 中获取历史记录,您可能需要用
包装您的组件在 React Router v6 中
import { useNavigate } from "react-router-dom";
function Invoices() {
let navigate = useNavigate();
return (
<div>
<NewInvoiceForm
onSubmit={async event => {
let newInvoice = await createInvoice(event.target);
navigate(`/invoices/${newInvoice.id}`);
}}
/>
</div>
);
}
那些在 React Router v4 中实现它时遇到问题的人。
这是一个从 redux 操作中浏览 React 应用程序的有效解决方案。
文件history.js
import createHistory from 'history/createBrowserHistory'
export default createHistory()
文件 App.js/Route.jsx
import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
<Route path="/test" component={Test}/>
</Router>
文件*another_file.js或redux文件
import history from './history'
history.push('/test') // This should change the URL and rerender Test component
感谢 GitHub 上的这条评论: ReactTraining issues comment
React Router v4+
假设您在初始渲染过程中不需要导航(您可以使用 <Redirect>
组件),这就是我们在应用程序中所做的。
定义一个空路由,returns null。这将允许您访问历史对象。您需要在定义 Router
的顶层执行此操作。
现在您可以做在 history 上可以做的所有事情,例如 history.push()
、history.replace()
、history.go(-1)
等!
import React from 'react';
import { HashRouter, Route } from 'react-router-dom';
let routeHistory = null;
export function navigateTo(path) {
if(routeHistory !== null) {
routeHistory.push(path);
}
}
export default function App(props) {
return (
<HashRouter hashType="noslash">
<Route
render={({ history }) => {
routeHistory = history;
return null;
}}
/>
{/* Rest of the App */}
</HashRouter>
);
}
这对我有用,不需要特殊导入:
<input
type="button"
name="back"
id="back"
class="btn btn-primary"
value="Back"
onClick={() => { this.props.history.goBack() }}
/>
您还可以在无状态组件中使用 useHistory
挂钩。文档中的示例:
import { useHistory } from "react-router"
function HomeButton() {
const history = useHistory()
return (
<button type="button" onClick={() => history.push("/home")}>
Go home
</button>
)
}
Note: Hooks were added in
react-router@5.1.0
and requirereact@>=16.8
在我的回答中,有三种不同的方法可以以编程方式重定向到路由。已经介绍了一些解决方案,但以下解决方案仅针对 功能组件 以及附加的演示应用程序。
使用以下版本:
react: 16.13.1
react-dom: 16.13.1
react-router: 5.2.0
react-router-dom: 5.2.0
typescript: 3.7.2
配置:
所以首先解决方案是使用HashRouter
,配置如下:
<HashRouter>
// ... buttons for redirect
<Switch>
<Route exact path="/(|home)" children={Home} />
<Route exact path="/usehistory" children={UseHistoryResult} />
<Route exact path="/withrouter" children={WithRouterResult} />
<Route exact path="/redirectpush" children={RedirectPushResult} />
<Route children={Home} />
</Switch>
</HashRouter>
来自 the documentation 关于 <HashRouter>
:
A
<Router>
that uses the hash portion of the URL (i.e.window.location.hash
) to keep your UI in sync with the URL.
解法:
- 使用
<Redirect>
推送使用useState
:
在功能组件中使用(RedirectPushAction
component from my repository) we can use useState
来处理重定向。棘手的部分是一旦重定向发生,我们需要将 redirect
状态设置回 false
。通过使用setTimeOut
延迟 0
我们正在等待 React 将 Redirect
提交给 DOM 然后取回按钮以便下次使用它。
请在下面找到我的示例:
const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
let render = null;
if (redirect) {
render = <Redirect to="/redirectpush" push={true} />
// In order wait until committing to the DOM
// and get back the button for clicking next time
setTimeout(() => setRedirect(false), 0);
}
return render;
}, [redirect]);
return <>
{handleRedirect()}
<button onClick={() => setRedirect(true)}>
Redirect push
</button>
</>
来自 <Redirect>
文档:
Rendering a
<Redirect>
will navigate to a new location. The new location will override the current location in the history stack, like server-side redirects (HTTP 3xx) do.
- 使用
useHistory
钩子:
在我的解决方案中有一个名为 UseHistoryAction
的组件,它表示以下内容:
let history = useHistory();
return <button onClick={() => { history.push('/usehistory') }}>
useHistory redirect
</button>
The
useHistory
hook gives us access to the history object which helps us programmatically navigate or change routes.
- 使用
withRouter
,从props
得到history
:
创建了一个名为WithRouterAction
的组件,显示如下:
const WithRouterAction = (props:any) => {
const { history } = props;
return <button onClick={() => { history.push('/withrouter') }}>
withRouter redirect
</button>
}
export default withRouter(WithRouterAction);
正在阅读 withRouter
文档:
You can get access to the
history
object's properties and the closest<Route>
's match via thewithRouter
higher-order component.withRouter
will pass updatedmatch
,location
, andhistory
props to the wrapped component whenever it renders.
演示:
为了更好地展示我已经用这些示例构建了一个 GitHub 存储库,请在下面找到它:
react-router-dom: 5.1.2
本网站有 3 个页面,所有页面均在浏览器中动态呈现。
虽然页面永远不会刷新,但请注意 React Router 如何 在您浏览网站时使 URL 保持最新。这个 保留浏览器历史记录,确保像后面这样的事情 按钮和书签正常工作
A Switch 遍历所有子节点 元素并呈现第一个其路径 匹配当前 URL。随时使用 你有多条路线,但你只想要一条 其中一次渲染
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
</Router>
);
}
// You can think of these components as "pages"
// in your app.
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function About() {
return (
<div>
<h2>About</h2>
</div>
);
}
function Dashboard() {
return (
<div>
<h2>Dashboard</h2>
</div>
);
}```
试试 React Hook Router,“react-router 的现代替代品”:
import { useRoutes, usePath, A} from "hookrouter";
要回答 OP 关于通过 select 框链接的问题,您可以这样做:
navigate('/about');
更新答案
我认为 React Hook Router 是一个很好的入门工具包,帮助我学习了路由,但我已经更新到 React Router 以了解其历史记录和查询参数处理。
import { useLocation, useHistory } from 'react-router-dom';
const Component = (props) => {
const history = useHistory();
// Programmatically navigate
history.push(newUrlString);
}
您将要导航的位置推入 location.history。
带有钩子的 React Router v6
import {useNavigate} from 'react-router-dom';
let navigate = useNavigate();
navigate('home');
并浏览浏览器历史记录,
navigate(-1); ---> Go back
navigate(1); ---> Go forward
navigate(-2); ---> Move two steps backward.
以编程方式在 class-based 个组件中导航。
import { Redirect } from "react-router-dom";
class MyComponent extends React.Component{
state = {rpath: null}
const goTo = (path) => this.setState({rpath: path});
render(){
if(this.state.rpath){
return <Redirect to={this.state.rpath}/>
}
.....
.....
}
}
如果您使用的是较新版本的 React,使用“useHistory”挂钩是最佳选择。
这已经提到我们可以使用 useNavigate()
useHistory
)中导航
import { useNavigate } from 'react-router-dom';
const myComponent = () => {
const navigate = useNavigate();
navigate('my_url');
...
}
但我在这里找不到的是调用导航出 React 组件,例如在 redux-saga
函数内导航页面到另一个页面。以防万一,如果你有同样的问题,这是我找到的。
在你的根组件中(我称之为 <App />
)
import { useNavigate } from 'react-router-dom';
import useBus from 'use-bus';
const App = () => {
const navigate = useNavigate();
useBus('@@ui/navigate', (action) => navigate(action.payload.url), []);
...
}
没有 React 组件(在我的例子中是 redux-saga
函数)
import { dispatch } from 'use-bus';
dispatch({ type: '@@ui/navigate', payload: { url: '/404' } });
希望对您有所帮助!
对于已经在使用 React Router v6 的用户,可以使用 react-router
提供的 useNavigate
钩子来完成。
使用这个钩子导航非常简单:
import { generatePath, useNavigate } from 'react-router';
navigate(-1); // navigates back
navigate('/my/path'); // navigates to a specific path
navigate(generatePath('my/path/:id', { id: 1 })); // navigates to a dynamic path, generatePath is very useful for url replacements
最新 react-router-dom v6
useHistory()
替换为 useNavigate()
。
您需要使用:
import { useNavigate } from 'react-router-dom';
const navigate = useNavigate();
navigate('/your-page-link');
为了简单起见,只需使用 useNavigate
最新版本的 react
Newfile.js
import { useNavigate } from "react-router-dom";
const Newfile = () => {
const navigate = useNavigate();
....
navigate("yourdesiredlocation");
....
}
export default Newfile;
在您的代码中使用上述 useNavigate
功能。