使用React Router以编程方式导航

通过react-router我可以使用Link元素来创建由react路由器本地处理的链接。

我在内部看到它调用this.context.transitionTo(...)

我想从下拉列表中进行导航,而不是从链接进行导航。 如何在代码中执行此操作? 这是什么this.context

我看到了Navigation混合器,但是没有混合器可以做到吗?


#1楼

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
};

注意:如果您的组件不是由呈现的,则this.props.history不存在。 您应该使用在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')

进一步阅读: 历史和导航


React-Router 1.xx答案

我不会介绍升级细节。 您可以在《 升级指南》中阅读有关内容

关于此问题的主要更改是从Navigation mixin到History的更改。 现在,它使用浏览器historyAPI更改路由,因此从现在开始我们将使用pushState()

这是使用Mixin的示例:

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

请注意,此“ History来自“ 球拍/历史记录”项目。 不是来自React-Router本身。

如果由于某种原因(也许由于ES6类)不想使用Mixin,则可以从this.props.history访问从路由器获得的历史记录。 仅路由器提供的组件可以访问它。 因此,如果要在任何子组件中使用它,则需要通过props将其作为属性向下传递。

您可以在其1.0.x文档中了解有关新版本的更多信息。

这是一个专门关于在组件外部导航的帮助页面

它建议获取参考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 (
Click me!
); } });

我无需调用.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 (
Click me!
); } } Authentication.contextTypes = { router: React.PropTypes.func.isRequired };

React-Router-Redux

注意:如果您使用Redux,还有另一个名为React-Router-Redux的项目,它使用与React-Redux相同的方法为您提供ReactRouter的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



#2楼

警告:此答案仅涵盖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 (
Click me!
); } });

带有上下文的陷阱是,除非您在类上定义contextTypes ,否则无法访问它。

至于什么是上下文,它是一个像道具一样的对象,它从父级传递到子级,但是隐式地传递下来,而不必每次都重新声明道具。 参见https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


#3楼

React-路由器v2

对于最新版本( v2.0.0-rc5 ),推荐的导航方法是直接推送到历史单例。 您可以在Components doc之外的导航中看到这一点。

相关摘录:

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

如果使用较新的react-router API,则需要在组件内部使用this.propshistory ,因此:

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

它还提供pushState但已记录的警告已弃用。

如果使用react-router-redux ,它提供了一个push函数,您可以像这样调度:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

但是,这只能用于更改URL,而不能实际导航到页面。


#4楼

这是在ES6上使用react-router v2.0.0 v2.0.0的方法 。 react-router已从mixins移开。

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}

#5楼

对于这一点,谁不控制服务器端,因此使用哈希路由器v2:

将您的历史记录放入单独的文件中(例如,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((
  
  ...
  
), 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()
  }
})

#6楼

对于ES6 + React组件,以下解决方案适用于我。

我关注了Felippe skinner,但添加了端到端解决方案来帮助像我这样的初学者。

以下是我使用的版本:

“反应路由器”:“ ^ 2.7.0”

“反应”:“ ^ 15.3.1”

以下是我的react组件,在其中我使用了react-router进行程序导航:

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
; } }; loginComp.contextTypes = { router: React.PropTypes.object.isRequired } module.exports = loginComp;

以下是我的路由器的配置:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(
          
            
            
            
            
            
          
        , document.getElementById('root'));

#7楼

随着即将推出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;


react-lego是一个示例应用程序,显示了如何使用/更新react-router ,并且包括导航该应用程序的示例功能测试。


#8楼

可能不是最好的方法,但是...使用react-router v4,以下Typescript可能会给您一些帮助。

在下面的呈现组件中,例如LoginPage ,可以访问router对象,只需调用router.transitionTo('/homepage')进行导航。

导航代码来自 。

"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 { render() { return(  ( React.createElement(this.props.component, this.props) )} /> ) } } ReactDOM.render(  {({ router }) => ( 
)}
, document.getElementById('app') );


#9楼

在当前的React版本(15.3)中, this.props.history.push('/location'); 为我工作,但显示以下警告:

browser.js:49警告:[react-router] props.historycontext.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;

#10楼

React-Router V4

如果您使用的是版本4,则可以使用我的库(Shameless插件),您可以在其中简单地调度一个动作,并且一切正常!

dispatch(navigateTo("/aboutUs"));

特里普勒


#11楼

在正常工作之前,我尝试了至少10种方法!

@Felipe Skinner的withRouter答案对我来说有点不知所措,而且我不确定是否要创建新的“ ExportedWithRouter”类名称。

大约是当前的React-Router 3.0.0和ES6,这是最简单,最干净的方法:

使用ES6的React-Router 3.xx:

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.xx中, 组件本身正在使用router.push ,因此您可以将传递标记的任何内容传递给它,例如:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'

#12楼

根据先前的答案
来自JoséAntonio Postigo和Ben Wheeler
新奇? 用打字稿
装饰器的使用
静态属性/字段

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{
    navigate: (to: string) => void;
    constructor(props: INavigatorProps) {
        super(props);
        let self = this;
        this.navigate = (to) => self.props.router.push(to);
    }
    render() {
        return (
            
  • this.navigate("/home")}> Home
  • this.navigate("/about")}> About
) } } /** * Non decorated */ export class Navigator2 extends Component { 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 (
  • this.navigate("/home")}> Home
  • this.navigate("/about")}> About
) } }

无论今天安装了什么npm。 “ react-router”:“ ^ 3.0.0”和
“ @ types / react-router”:“ ^ 2.0.41”


#13楼

带有钩子的React Router v5.1.0

如果您使用React> 16.8.0和功能组件,则在React Router> 5.1.0中有一个新的useHistory挂钩。

import { useHistory } from "react-router-dom";

function HomeButton() {
  let history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    
  );
}

反应路由器v4

使用React Router v4,您可以采用三种方法在组件内进行编程路由。

  1. 使用withRouter高阶组件。
  2. 使用合成并渲染
  3. 使用context

React Router主要是history库的包装器。 history处理与浏览器window.history 。交互的history ,以及浏览器和哈希历史记录。 它还提供了内存历史记录,这对于没有全局历史记录的环境很有用。 这在使用Node进行移动应用程序开发( react-native )和单元测试中特别有用。

history实例有两种导航方法: pushreplace 。 如果您将history视为访问过的位置数组,则push将向该位置添加新位置,而replace将用新位置replace该数组中的当前位置。 通常,您在导航时会希望使用push方法。

在早期版本的React Router中,您必须创建自己的history实例,但是在v4中, 组件将为您创建浏览器,哈希和内存实例。 React Router通过router对象下的上下文使与路由器关联的history实例的属性和方法可用。

1.使用withRouter高阶组件

withRouter高阶组件将注入history对象作为该组件的支持。 这使您无需处理context即可访问pushreplace方法。

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  
))

2.使用合成并渲染

组件不仅用于匹配位置。 您可以渲染无路径的路线, 它将始终与当前位置匹配组件传递与withRouter相同的道具,因此您将能够通过history道具访问history方法。

import { Route } from 'react-router-dom'

const Button = () => (
   (
    
  )} />
)

3.使用上下文*

但是你可能不应该

最后一个选项是只有在您熟悉使用React的上下文模型时才应使用的选项。 尽管上下文是一个选项,但应该强调的是上下文是不稳定的API,React在其文档中有“ 为什么不使用上下文”一节。 因此,使用后果自负!

const Button = (props, context) => (
  
)

// 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是最简单的实现方式,因此对于大多数用例来说,它们是最好的选择。


此外,您可以从以下链接中获得有关路由,URL参数和嵌套路由的更多知识。

在React JS中路由
-逐步说明如何在ReactJS中集成react-router

使用React Router的URL参数
-在这里您可以了解如何使用React Router设置URL参数。 URL参数路由的主要用途是根据其动态URL呈现相同的组件。

React JS中的嵌套路由
-如果要在主路径中加载子路径,则必须创建嵌套路径。 这是它的现场示例。

希望能帮到你!


#14楼

要以编程方式进行导航,您需要将新的历史记录送到 componentprops.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 (
      
) } } export default App;

#15楼

React-Router 4.x回答:

最后,我希望有一个历史对象,甚至可以携带外部组件。 我想做的是拥有一个按需导入的history.js文件,并对其进行操作。

您只需要将BrowserRouter更改为Router,然后指定历史记录BrowserRouter即可。 除了拥有自己的历史对象可以随意操作之外,这对您没有任何改变。

您需要安装历史记录 , 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 Previous;
    }
}

编辑2018年4月16日:

如果必须从实际从Route组件渲染的组件中导航,则还可以从props访问历史记录,如下所示:

BasicComponent.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return Previous;
    }
}

#16楼

如果您使用哈希或浏览器历史记录,则可以

hashHistory.push('/login');
browserHistory.push('/login');

#17楼

React-Router v4ES6中

您可以使用withRouterthis.props.history.push

import {withRouter} from 'react-router-dom';

class Home extends Component {

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

export default withRouter(Home);

#18楼

只需使用this.props.history.push('/where/to/go');


#19楼

反应路由器V4

tl:dr;

if (navigate) {
  return 
}

简单且声明性的答案是,您需要将setState()结合使用

push:布尔值-设置为 true时,重定向会将新条目推入历史记录,而不是替换当前条目。


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 
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      
) } }

完整的例子在这里 。 在这里阅读更多。

PS。 该示例使用ES7 +属性初始化程序来初始化状态。 如果您有兴趣,也请在这里查看。


#20楼

也许不是最好的解决方案,但可以完成工作:

import { Link } from 'react-router-dom';

// create functional component Post
export default Post = () => (
    
);

基本上,与一个动作(在这种情况下为后删除)相关的逻辑最终将调用重定向触发器。 这不是理想的,因为您将在标记中添加DOM节点“触发”,以便您在需要时可以方便地调用它。 另外,您将直接与DOM交互,而在React组件中可能不需要DOM。

不过,这种重定向并不是经常需要的。 因此,组件标记中的一个或两个额外的隐藏链接不会对您造成太大的伤害,特别是如果给它们提供有意义的名称。


#21楼

正确的答案是在撰写本文时适合我的

this.context.router.history.push('/');

但是您需要将PropTypes添加到您的组件中

Header.contextTypes = {
  router: PropTypes.object.isRequired
}
export default Header;

不要忘记导入PropTypes

import PropTypes from 'prop-types';

#22楼

如果发生配对RR4 W /通过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挂钩以响应组件,可能会更好。


#23楼

要将withRouter与基于类的组件一起使用,请尝试以下类似方法。 别忘了更改export语句以与withRouter一起使用:

import { withRouter } from 'react-router-dom'

class YourClass extends React.Component {
  yourFunction = () => {
    doSomeAsyncAction(() =>
      this.props.history.push('/other_location')
    )
  }

  render() {
    return (
      
) } } export default withRouter(YourClass);

#24楼

在React Router v4中。 我遵循两种方式以编程方式进行路由。

1. this.props.history.push("/something/something")
2. this.props.history.replace("/something/something")

第二

替换历史记录堆栈上的当前条目

要获取道具的历史记录,您可能需要使用

与路由器


#25楼

那些在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'
...

 

another_file.js或redux文件

import history from './history' 

history.push('/test') // this should change the url and re-render Test component

感谢此评论: ReactTraining问题评论


#26楼

简单的反应路由:

  • 代码框

链接到我的代码沙箱。 它还有其他一些简单的react-redux程序。


#27楼

对于React Router v4 +

假设您不需要在初始渲染过程中进行导航(可以使用组件),这就是我们在应用程序中所做的。

定义一个返回null的空路由,这将使您能够访问历史对象。 您需要在定义Router的顶层执行此操作。

现在,您可以执行历史上可以完成的所有操作,例如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 (
    
       {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    
  );
}

#28楼

这对我有用,不需要特殊的进口:

 { this.props.history.goBack() }} 
/>

#29楼

您还可以在无状态组件中使用useHistory挂钩。 文档中的示例。

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

  return (
    
  )
}

注意:钩子已添加到[email protected]并且需要react@>=16.8


#30楼

因此,在我的回答中,有3种不同的方式可以以编程方式重定向到路线。 已经介绍了一些解决方案,但以下解决方案仅针对带有附加演示应用程序的功能组件

使用以下版本:

反应: 16.12.0

react-dom: 16.12.0

反应路由器: 5.1.2

react-router-dom: 5.1.2

打字稿: 3.7.2

组态:

因此,首先解决方案是使用HashRouter ,其配置如下:


    // ... buttons for redirect

    
      
      
      
      
      
    

从有关的文档中 :

使用URL的哈希部分(即window.location.hash )使您的UI与URL保持同步。

解决方案:

  1. 使用推送使用useState

在功能组件(我的存储库中的RedirectPushAction组件)中使用,我们可以使用useState来处理重定向。 棘手的部分是,一旦发生重定向,我们需要将redirect状态设置回false 。 通过将setTimeOut0延迟,我们等待,直到React将Redirect提交到DOM,然后取回该按钮以便下次使用。

请在下面找到我的示例:

const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
    let render = null;
    if (redirect) {
        render = 

        // in order wait until commiting to the DOM
        // and get back the button for clicking next time
        setTimeout(() => setRedirect(false), 0);
    }
    return render;
}, [redirect]);

return <>
    {handleRedirect()}
    

文档中:

渲染将导航到新位置。 新位置将覆盖历史记录堆栈中的当前位置,就像服务器端重定向(HTTP 3xx)一样。

  1. 使用useHistory钩子:

在我的解决方案中,有一个名为UseHistoryAction的组件,它表示以下内容:

let history = useHistory();

return 

useHistory挂钩使我们可以访问历史记录对象,这有助于我们以编程方式导航或更改路线。

  1. 使用withRouter ,从props获取history

创建了一个名为WithRouterAction组件,显示如下:

const WithRouterAction = (props:any) => {
    const { history } = props;

    return 
}

export default withRouter(WithRouterAction);

withRouter文档中阅读:

您可以通过withRouter高阶组件访问history对象的属性和最接近的匹配项。 每当呈现时, withRouter都会将更新的matchlocationhistory道具传递给包装的组件。

演示:

为了更好地表示,我用这些示例构建了一个GitHub存储库,请在下面找到它:

https://github.com/norbitrial/react-router-programmatically-redirect-examples

我希望这有帮助!

你可能感兴趣的:(reactjs,react-router)