Programmatically navigate using react router
使用
我在内部看到它调用
我想进行导航,但不是从链接,例如下拉选择。 我怎么能在代码中这样做? 什么是
我看到了
React Router v4
使用React Router的v4,您可以采用三种方法在组件内进行编程路由。
React Router主要是
在早期版本的React Router中,您必须创建自己的
1.使用
1 2 3 4 5 6 7 8 9 10 11 | 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.使用合成并渲染
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的上下文模型时才能使用的选项。尽管上下文是一种选择,但应该强调上下文是一个不稳定的API,React在其文档中有一节"不使用上下文"。所以使用风险自负!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 4.0.0+ Answer
在4.0及更高版本中,使用历史记录作为组件的支柱。
1 2 3 | class Example extends React.Component { // use `this.props.history.push('/some/path')` here }; |
注意:如果您的组件未由
React-Router 3.0.0+ Answer
在3.0及以上版本中,使用路由器作为组件的支柱。
1 2 3 | class Example extends React.Component { // use `this.props.router.push('/some/path')` here }; |
React-Router 2.4.0+ Answer
在2.4及更高版本中,使用更高阶的组件将路由器作为组件的支柱。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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模块可以访问
现在您可以访问浏览器历史记录,因此您可以执行推送,替换等操作...
进一步阅读:
历史和
导航
React-Router 1.x.x Answer
我不打算升级细节。您可以在"升级指南"中阅读相关内容
这里问题的主要变化是从导航mixin到History的变化。现在它正在使用浏览器historyAPI来改变路由,所以从现在开始我们将使用
这是使用Mixin的例子:
1 2 3 4 5 6 | var Example = React.createClass({ mixins: [ History ], navigateToHelpPage () { this.history.pushState(null, `/help`); } }) |
请注意,此
如果由于某种原因(可能是因为ES6类)不想使用Mixin,那么您可以从
您可以在1.0.x文档中阅读有关新版本的更多信息
这是一个专门关于在组件外部导航的帮助页面
它建议抓取一个引用
React-Router 0.13.x Answer
我遇到了同样的问题,只能通过react-router附带的Navigation mixin找到解决方案。
这就是我做到的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import React from 'react'; import {Navigation} from 'react-router'; let Authentication = React.createClass({ mixins: [Navigation], handleClick(e) { e.preventDefault(); this.transitionTo('/'); }, render(){ return (Click me!); } }); |
我能够在不需要访问
或者你可以尝试花哨的ES6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 (Click me!); } } 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
1 2 3 | import { goBack } from 'react-router-redux' export const onBackPress = () => (dispatch) => dispatch(goBack()) |
./viewcomponent.js
1 2 3 4 5 6 7 8 9 10 | <button disabled={submitting} className="cancel_button" onClick={(e) => { e.preventDefault() this.props.onBackPress() }} > CANCEL </button> |
React-Router v2
对于最新版本(
相关摘录:
1 2 | import { browserHistory } from 'react-router'; browserHistory.push('/some/path'); |
如果使用较新的react-router API,则需要在组件内部使用
1 | this.props.history.push('/some/path'); |
它还提供
如果使用
1 2 | import { push } from 'react-router-redux'; this.props.dispatch(push('/some/path')); |
但是,这可能仅用于更改URL,而不是实际导航到页面。
以下是使用ES6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 } |
React-Router 4.x Answer :
在我的结尾,我喜欢有一个历史对象,我甚至可以携带外部组件。我喜欢做的是拥有一个我按需导入的单个history.js文件,并且只是操作它。
您只需将
您需要安装历史记录,
示例用法,ES6表示法:
history.js
1 2 | import createBrowserHistory from 'history/createBrowserHistory' export default createBrowserHistory() |
BasicComponent.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import React, { Component } from 'react'; import history from './history'; class BasicComponent extends Component { goToIndex(e){ e.preventDefault(); history.push('/'); } render(){ return Previous; } } |
EDIT April 16th, 2018 :
如果必须从实际从
BasicComponent.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | import React, { Component } from 'react'; class BasicComponent extends Component { navigate(e){ e.preventDefault(); this.props.history.push('/url'); } render(){ return Previous; } } |
对于这个,谁不控制服务器端,因此使用哈希路由器v2:
将您的历史记录放入单独的文件中(例如app_history.js ES6):
1 2 3 4 5 | import { useRouterHistory } from 'react-router' import { createHashHistory } from 'history' const appHistory = useRouterHistory(createHashHistory)({ queryKey: false }); export default appHistory; |
到处使用它!
您对react-router(app.js ES6)的入口点:
1 2 3 4 5 6 7 8 9 10 | 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):
1 2 3 4 5 6 7 8 9 10 | 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() } }) |
React Router V4
TL:博士;
1 2 3 | if (navigate) { return <Redirect to="/" push={true} /> } |
简单和声明性的答案是您需要将
push: boolean - when true, redirecting will push a new entry onto the history instead of replacing the current one.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 ( <button onClick={() => this.setState({ navigate: true })}> Home </button> ) } } |
完整的例子。
在这里阅读更多。
PS。该示例使用ES7 +属性初始化程序初始化状态。如果你有兴趣,也可以看看这里。
Warning: this answer covers only ReactRouter versions before 1.0
I will update this answer with 1.0.0-rc1 use cases after!
你也可以不用mixin来做到这一点。
1 2 3 4 5 6 7 8 9 10 11 12 | let Authentication = React.createClass({ contextTypes: { router: React.PropTypes.func }, handleClick(e) { e.preventDefault(); this.context.router.transitionTo('/'); }, render(){ return (Click me!); } }); |
上下文的问题在于,除非您在类上定义
至于什么是上下文,它是一个对象,就像道具一样,从父对象传递到子对象,但它是隐式传递下来的,而不必每次都重新声明道具。请参阅https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html
在事情正常之前我尝试了至少10种方法!
@Felipe Skinner的
这是最简单,最干净的方法,大约是当前的React-Router 3.0.0和ES6:
React-Router 3.x.x with ES6:
1 2 3 4 5 6 7 8 | 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); |
或者,如果它不是您的默认类,则导出如下:
1 2 | withRouter(Example); export { Example }; |
请注意,在3.x.x中,
1 | this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})' |
要以编程方式进行导航,您需要将新历史记录推送到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //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 ( <button onClick={this.handleClick}> Redirect!!! </button> ) } } export default App; |
请找到以下工作代码:
正如本文所讨论的,使用react Router进行导航是一种非常简单的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Register extends React.Component { state = { toDashboard: false, } handleSubmit = (user) => { saveUser(user) .then(() => this.setState(() => ({ toDashboard: true }))) } render() { if (this.state.toDashboard === true) { return <Redirect to='/dashboard' /> } return ( Register <Form onSubmit={this.handleSubmit} /> ) } } |
<重定向/>是
Composable ? Declarative ? user event -> state change -> re-render ?
注册组件由React Router呈现,我们的代码看起来像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class Register extends React.Component { handleSubmit = (user) => { saveUser(user).then(() => this.props.history.push('/dashboard') )) } render() { return ( Register <Form onSubmit={this.handleSubmit} /> ) } } |
通过添加withRouter,它看起来像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import { withRouter } from 'react-router-dom' class Register extends React.Component { handleSubmit = (user) => { saveUser(user).then(() => this.props.history.push('/dashboard') )) } render() { return ( Register <Form onSubmit={this.handleSubmit} /> ) } } export default withRouter(Register) |
有两种方法可以使用React Router和history.push以编程方式进行导航。您使用的主要取决于您和您的特定用例,尽管我尝试使用Redirect。
对于ES6 + React组件,以下解决方案适用于我。
我跟着Felippe skinner,但添加了一个端到端的解决方案,以帮助像我这样的初学者。
以下是我使用的版本:
"react-router":"^2.7.0"
"react":"^15.3.1"
下面是我的反应组件,我使用react-router进行编程导航:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 // skipping html code <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button> ; } }; loginComp.contextTypes = { router: React.PropTypes.object.isRequired } module.exports = loginComp; |
以下是我的路由器的配置:
1 2 3 4 5 6 7 8 9 10 11 | 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,下面的Typescript可以给出一些想法。
在下面的渲染组件中,例如
导航代码取自https://react-router.now.sh/Match。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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 }) => ( <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} /> )} </Router>, document.getElementById('app') ); |
In React-Router v4 and ES6
您可以使用
1 2 3 4 5 6 7 8 9 10 | import {withRouter} from 'react-router-dom'; class Home extends Component { componentDidMount() { this.props.history.push('/redirect-to'); } } export default withRouter(Home); |
要将
不要忘记将export语句更改为使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class YourClass extends React.Component { yourFunction = () => { doSomeAsyncAction(() => this.props.history.push('/other_location') ) } render() { return ( <Form onSubmit={ this.yourFunction } /> ) } } export default withRouter(YourClass); |
随着React-Router v4的出现,现在有了一种新方法。
1 2 3 4 5 6 7 8 | 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是一个示例应用程序,显示如何使用/更新react-router,它包括导航应用程序的示例功能测试。
根据以前的答案
来自JoséAntonioPostigo和Ben Wheeler
新奇?将在Typescript中编写
和装饰的使用
或静态属性/字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | 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。
"react-router":"^ 3.0.0"和
"@ types / react-router":"^ 2.0.41"
在反应路由器v4中。我按照这两种方式以编程方式进行路由。
1 2 | 1. this.props.history.push("/something/something") 2. this.props.history.replace("/something/something") |
第二
Replaces the current entry on the history stack
要获取道具的历史记录,您可能需要使用包装
withRouter https://reacttraining.com/react-router/core/api/withRouter
使用当前的React版本(15.3),
browser.js:49 Warning: [react-router]
props.history and
context.history are deprecated. Please usecontext.router .
我用这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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; |
如果您使用哈希或浏览器历史记录,那么您可以这样做
1 2 | hashHistory.push('/login'); browserHistory.push('/login'); |
React-Router V4
如果您使用的是版本4,那么您可以使用我的库(无耻插件),您只需发送一个动作,一切正常!
1 | dispatch(navigateTo("/aboutUs")); |
https://www.npmjs.com/package/trippler
那些在react-router v4上实现这个问题的人。
这是一个工作解决方案,用于从redux操作中导航react应用程序。
history.js
1 2 3 | import createHistory from 'history/createBrowserHistory' export default createHistory() |
App.js / Route.jsx
1 2 3 4 5 6 | import { Router, Route } from 'react-router-dom' import history from './history' ... <Router history={history}> <Route path="/test" component={Test}/> </Router> |
another_file.js或redux文件
1 2 3 | import history from './history' history.push('/test') // this should change the url and re-render Test component |
感谢这个评论:
ReactTraining发表评论
如果碰巧通过react-router-redux配对RR4 w / redux,那么使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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钩子来反应组件可能会更好。
也许不是最好的解决方案,但它完成了工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import { Link } from 'react-router-dom'; // create functional component Post export default 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> ); |
基本上,与一个动作相关联的逻辑(在这种情况下是删除后)将最终调用重定向的触发器。这不是理想的,因为您将向标记添加DOM节点"触发器",以便您可以在需要时方便地调用它。此外,您将直接与DOM交互,在可能不需要的React组件中。
但是,通常不需要这种类型的重定向。因此,组件标记中的一个或两个额外的隐藏链接不会对此造成太大影响,特别是如果您给它们提供有意义的名称。
在撰写本文时,正确的答案适合我
1 | this.context.router.history.push('/'); |
但是您需要将PropTypes添加到组件中
1 2 3 4 | Header.contextTypes = { router: PropTypes.object.isRequired } export default Header; |
不要忘记导入PropTypes
1 | import PropTypes from 'prop-types'; |
For React Router v4+
假设您不需要在初始渲染期间导航(可以使用
定义一个返回null的空路由,这将允许您获取对历史对象的访问权限。您需要在定义
现在你可以做所有可以在历史上完成的事情,如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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> ); } |
只需使用
简单的反应路由:
- https://codesandbox.io/s/lxq0qj7qnl
链接到我的代码沙箱。
它还有一些简单的react-redux程序。