使用 React 路由器以编程方式导航
Posted
技术标签:
【中文标题】使用 React 路由器以编程方式导航【英文标题】:Programmatically navigate using React router 【发布时间】:2015-09-13 18:08:41 【问题描述】:使用react-router
,我可以使用Link
元素来创建由反应路由器本机处理的链接。
我看到它在内部调用this.context.transitionTo(...)
。
我想做一个导航。不是来自链接,而是来自下拉选择(例如)。我怎样才能在代码中做到这一点? this.context
是什么?
我看到了Navigation
mixin,但是如果没有mixins
,我可以这样做吗?
【问题讨论】:
这里是react router v4官方文档教程的链接:reacttraining.com/react-router/web/guides/scroll-restoration 你可以查看这个答案***.com/questions/44127739/… 【参考方案1】:带钩子的 React Router v5.1.0
如果您使用 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 路由器 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 使与您的路由器关联的 history
实例的属性和方法可通过上下文在 router
对象下使用。
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
相同的属性,因此您将能够通过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 的 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 是实现起来最简单的选择,因此对于大多数用例来说,它们是您最好的选择。
【讨论】:
我尝试以这种方式使用方法 1 withRouter(( history ) => console.log("hhhhhhhh"); history.push('/bets') );但它从未与路由器 4 一起使用 什么!?我可以只使用withRouter
而不是通过我的所有组件传递history
吗?哎呀,我需要花更多时间阅读文档...
如何在不将行为附加到 Button 或其他 DOM 元素的情况下只运行 history.push('/new-location')
?
context
在 React 16 中不再是实验性的。
更新:对于那些使用 eact-router-dom v6 的用户应该使用 useNavigate() 而不是 useHistory()。有关更多详细信息,请参阅以下答案。 ***.com/a/66971821/12572265【参考方案2】:
React-Router v6+回答
您可以使用新的useNavigate
挂钩。 useNavigate
钩子返回一个可用于编程导航的函数。
来自反应路由器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+ 答案(使用钩子和 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+回答
在 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+回答
在 3.0 及以上版本中,使用路由器作为组件的道具。
class Example extends React.Component
// use `this.props.router.push('/some/path')` here
;
React-Router 2.4.0+回答
在 2.4 及以上版本中,使用高阶组件来获取路由器作为组件的道具。
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+回答
此版本向后兼容 1.x,因此无需升级指南。只需浏览示例就足够了。
也就是说,如果您想切换到新模式,您可以使用路由器内部的 browserHistory 模块访问
import browserHistory from 'react-router'
现在您可以访问浏览器历史记录,因此您可以执行推送、替换等操作...例如:
browserHistory.push('/some/path')
进一步阅读: Histories 和 Navigation
React-Router 1.x.x回答
我不会详细介绍升级细节。你可以在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 类),那么你可以从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 答案
我遇到了同样的问题,只能使用 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>);
);
我无需访问.context
就可以拨打transitionTo()
或者你可以试试花哨的 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
注意:如果你使用 Redux,还有另一个项目叫做 React-Router-Redux 给你 ReactRouter 的 redux 绑定,使用的方法与 React-Redux 确实
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>
【讨论】:
非常感谢。文档很难搜索到,即使您知道要查找的内容,在 useNavigate 函数中使用 replace 的简单和有用的功能也很难找到。【参考方案3】: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,而不是实际导航到页面。
【讨论】:
不要忘记,较新的 API 不使用import browserHistory from './react-router'
,而是使用 import createBrowserHistory from 'history/lib/createBrowserHistory'
创建历史记录。稍后,您可以通过 components 属性访问 history
:this.props.history('/some/path')
【参考方案4】:
以下是使用react-router v2.0.0
和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
【讨论】:
【参考方案5】: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>;
【讨论】:
【参考方案6】:对于这个,谁不控制服务器端,因此使用哈希路由器 v2:
将您的 history 放入单独的文件中(例如 app_history.js ES6):
import useRouterHistory from 'react-router'
import createHashHistory from 'history'
const appHistory = useRouterHistory(createHashHistory)( queryKey: false );
export default appHistory;
并在任何地方使用它!
你的 react-router (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()
)
【讨论】:
【参考方案7】:反应路由器 v6
我有一段时间没接触 React,但要感谢并强调 the comment below by Shimrit Snapir:
on React-Router 6.0 <Redirect /> changed to <Navigate />
反应路由器 V4
tl:dr;
if (navigate)
return <Redirect to="/" push=true />
简单而明确的答案是您需要结合使用<Redirect to=URL push=boolean />
和setState()
push: boolean - 当为真时,重定向会将新条目推送到历史记录中,而不是替换当前条目。
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>
)
一个完整的例子是here。阅读更多here。
PS。该示例使用ES7+ Property Initializers 来初始化状态。如果你有兴趣,也可以看看here。
【讨论】:
【参考方案8】:警告:此答案仅涵盖 1.0 之前的 ReactRouter 版本
之后我会用 1.0.0-rc1 用例更新这个答案!
你也可以不使用 mixins。
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>);
);
上下文的问题是除非你在类上定义contextTypes
,否则它是不可访问的。
至于什么是context,它是一个对象,就像props一样,从parent传给child,但是是隐式传递的,不需要每次都重新声明props。见https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html
【讨论】:
【参考方案9】:这是最简单和最干净的方法,大约是当前的 React-Router 3.0.0 和 ES6:
带有 ES6 的 React-Router 3.x.x:
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);
或者,如果它不是你的默认类,导出如下:
withRouter(Example);
export Example ;
请注意,在 3.x.x 中,<Link>
组件本身正在使用 router.push
,因此您可以传递任何可以传递 <Link to=
标记的内容,例如:
this.props.router.push(pathname: '/some/path', query: key1: 'val1', key2: 'val2')'
【讨论】:
【参考方案10】:要以编程方式进行导航,您需要将新的 history 推送到 component
中的 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;
【讨论】:
【参考方案11】:对于 ES6 + React 组件,以下解决方案对我有用。
我跟随 Felippe skinner,但添加了端到端解决方案来帮助像我这样的初学者。
以下是我使用的版本:
“反应路由器”:“^2.7.0”
“反应”:“^15.3.1”
下面是我使用 react-router 编程导航的 react 组件:
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'));
【讨论】:
【参考方案12】:这可能不是最好的方法,但是...使用 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')
);
【讨论】:
【参考方案13】:在 React Router v4 中,我遵循这两种方式以编程方式进行路由。
this.props.history.push("/something/something")
this.props.history.replace("/something/something")
第二个
替换历史堆栈上的当前条目
要获取 props 中的历史记录,您可能需要用
包装组件withRouter
在 React 路由器 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>
);
Getting Started with React Router v6
【讨论】:
【参考方案14】:在 React-Router v4 和 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);
【讨论】:
【参考方案15】:要将withRouter
与基于类的组件一起使用,请尝试以下类似操作。
不要忘记将导出语句更改为使用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);
【讨论】:
【参考方案16】:随着 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 是一个显示how to use/update react-router 的示例应用程序,它包含用于导航应用程序的示例功能测试。
【讨论】:
这对于从渲染函数导航非常有用,但我想知道如何从生命周期钩子或 redux 之类的东西导航?【参考方案17】:基于之前的answers from José Antonio Postigoand Ben Wheeler:
新奇?用 TypeScript 编写并使用 decorators 或一个静态属性/字段
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"
【讨论】:
【参考方案18】:如果您使用的是哈希或浏览器历史记录,那么您可以这样做
hashHistory.push('/login');
browserHistory.push('/login');
【讨论】:
【参考方案19】:使用当前的 React 版本 (15.3),this.props.history.push('/location');
为我工作,但它显示以下警告:
browser.js:49 警告:[react-router]
props.history
和context.history
已弃用。请使用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;
【讨论】:
【参考方案20】: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.
【讨论】:
【参考方案21】:那些在 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
【讨论】:
【参考方案22】:您还可以在无状态组件中使用useHistory
挂钩。文档中的示例:
import useHistory from "react-router"
function HomeButton()
const history = useHistory()
return (
<button type="button" onClick=() => history.push("/home")>
Go home
</button>
)
注意:钩子是在
react-router@5.1.0
中添加的,需要react@>=16.8
【讨论】:
好电话,你能注意哪个版本的 react-router 和 react 指的是哪个版本吗?这是一项并非始终可用的新更改【参考方案23】:React-Router V4
如果您使用的是版本 4,那么您可以使用我的库(shameless 插件),您只需在其中调度一个操作,一切正常!
dispatch(navigateTo("/aboutUs"));
trippler
【讨论】:
【参考方案24】:以编程方式在基于类的组件中导航。
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/>
.....
.....
【讨论】:
【参考方案25】:在撰写本文时,正确答案对我来说
this.context.router.history.push('/');
但是你需要将 PropTypes 添加到你的组件中
Header.contextTypes =
router: PropTypes.object.isRequired
export default Header;
别忘了导入 PropTypes
import PropTypes from 'prop-types';
【讨论】:
【参考方案26】:在我的回答中,可以通过三种不同的方式以编程方式重定向到路由。一些解决方案已经介绍过,但以下解决方案仅针对功能组件以及附加的演示应用程序。
使用以下版本:
反应:16.13.1
react-dom:16.13.1
反应路由器:5.2.0
react-router-dom:5.2.0
打字稿: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>
:
<Router>
使用 URL 的哈希部分(即window.location.hash
)来使您的 UI 与 URL 保持同步。
解决方案:
-
使用
<Redirect>
推送使用useState
:
在功能组件(我的存储库中的RedirectPushAction
组件)中使用,我们可以使用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>
文档:
渲染
<Redirect>
将导航到新位置。新位置将覆盖历史堆栈中的当前位置,就像服务器端重定向 (HTTP 3xx) 一样。
-
使用
useHistory
钩子:
在我的解决方案中有一个名为 UseHistoryAction
的组件,它代表以下内容:
let history = useHistory();
return <button onClick=() => history.push('/usehistory') >
useHistory redirect
</button>
useHistory
钩子让我们可以访问历史对象,这有助于我们以编程方式导航或更改路线。
-
使用
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
文档:
您可以通过
withRouter
高阶组件访问history
对象的属性和最接近的<Route>
匹配项。withRouter
将在渲染时将更新的match
、location
和history
属性传递给被包装的组件。
演示:
为了更好地展示我已经使用这些示例构建了一个 GitHub 存储库,请在下面找到它:
React Router Programmatically Redirect Examples
【讨论】:
【参考方案27】:改用React Hook Router,“react-router 的现代替代品”:
import useRoutes, usePath, A from "hookrouter";
要回答 OP 关于通过选择框进行链接的问题,您可以这样做:
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。
【讨论】:
【参考方案28】:也许不是最好的解决方案,但它可以完成工作:
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>
);
基本上,与一个操作相关联的逻辑(在本例中为删除后)最终会调用重定向触发器。这并不理想,因为您将在标记中添加DOM 节点“触发器”,以便在需要时方便地调用它。此外,您将直接与 DOM 进行交互,这在 React 组件中可能是不需要的。
不过,这种类型的重定向并不经常需要。因此,在组件标记中添加一两个额外的隐藏链接不会造成太大伤害,尤其是如果您给它们起有意义的名称。
【讨论】:
【参考方案29】:如果您碰巧通过 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 组件可能会更好。
【讨论】:
【参考方案30】:这对我有用,不需要特殊导入:
<input
type="button"
name="back"
id="back"
class="btn btn-primary"
value="Back"
onClick=() => this.props.history.goBack()
/>
【讨论】:
以上是关于使用 React 路由器以编程方式导航的主要内容,如果未能解决你的问题,请参考以下文章
如何在 react-router 中以编程方式进行服务器端路由?
Uncaught TypeError: (0 , _reactRouter.withRouter) 在 react-router 2.4.0 中以编程方式导航路由时不是一个函数