使用 React 路由器以编程方式导航

Posted

技术标签:

【中文标题】使用 React 路由器以编程方式导航【英文标题】:Programmatically navigate using React router 【发布时间】:2016-10-10 17:01:45 【问题描述】:

使用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 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 路由器 v4

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

    使用withRouter 高阶组件。 使用合成并渲染&lt;Route&gt; 使用context

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

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

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

1。使用withRouter高阶组件

withRouter 高阶组件将注入 history 对象作为组件的 prop。这允许您访问pushreplace 方法,而无需处理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。使用合成并渲染&lt;Route&gt;

&lt;Route&gt; 组件不仅仅用于匹配位置。您可以渲染一条无路径路线,并且它将始终与当前位置匹配&lt;Route&gt; 组件传递与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
;

注意:如果您的组件不是由&lt;Route&gt; 呈现的,则 this.props.history 不存在。您应该使用 &lt;Route path="..." component=YourComponent/&gt; 在 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.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,而不是实际导航到页面。

【讨论】:

不要忘记,较新的 API 不使用 import browserHistory from './react-router',而是使用 import createBrowserHistory from 'history/lib/createBrowserHistory' 创建历史记录。稍后,您可以通过 components 属性访问 historythis.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 属性。这对您没有任何改变,只是您拥有自己的历史对象,您可以随意操作。

你需要安装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 &lt;Redirect /&gt; changed to &lt;Navigate /&gt;

反应路由器 V4

tl:dr;

if (navigate) 
  return <Redirect to="/" push=true />

简单而明确的答案是您需要结合使用&lt;Redirect to=URL push=boolean /&gt;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 中,&lt;Link&gt; 组件本身正在使用 router.push,因此您可以传递任何可以传递 &lt;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 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);

【讨论】:

【参考方案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.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;

【讨论】:

【参考方案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@&gt;=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关于&lt;HashRouter&gt;

&lt;Router&gt; 使用 URL 的哈希部分(即window.location.hash)来使您的 UI 与 URL 保持同步。

解决方案:

    使用&lt;Redirect&gt;推​​送使用useState

在功能组件(我的存储库中的RedirectPushAction 组件)中使用,我们可以使用useState 来处理重定向。棘手的部分是一旦发生重定向,我们需要将redirect 状态设置回false。通过使用 setTimeOut0 延迟,我们等待 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>
</>

来自&lt;Redirect&gt; 文档:

渲染&lt;Redirect&gt; 将导航到新位置。新位置将覆盖历史堆栈中的当前位置,就像服务器端重定向 (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 对象的属性和最接近的&lt;Route&gt; 匹配项。 withRouter 将在渲染时将更新的 matchlocationhistory 属性传递给被包装的组件。

演示:

为了更好地展示我已经使用这些示例构建了一个 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 中以编程方式导航路由时不是一个函数

以编程方式反应路由器 v4 导航

以编程方式反应导航更改选项卡顺序

反应路由器,以编程方式导航时传递数据?

以编程方式重定向到反应路由器 v6 中的路由的问题