使用React Router以编程方式导航


1427

通过使用react-router我可以使用Link元素创建由React Router本机处理的链接。

我在内部看到它的呼唤this.context.transitionTo(...)

我想导航。不是来自链接,而是来自下拉菜单(例如)。如何在代码中执行此操作?什么this.context

我看到了Navigationmixin,但是如果没有我可以这样做mixins吗?


26
@SergioTapia请记住,这个问题跨越了react-router的主要版本,React的主要版本以及javascript的主要版本
George Mauer

5
这是React
chitzui


4
很高兴您能回答这个问题,但很遗憾,它必须如此复杂。在Web应用程序中浏览应该很容易并且有据可查。VueJS使它变得微不足道。每个组件都会自动注入路由器实例。他们的文档中对此有明确定义的部分。 router.vuejs.org/guide/essentials/navigation.html我在很多方面都喜欢React,但有时过于复杂。</ rant>
colefner

7
@GeorgeMauer你是对的。这不是这个社区的目的。这是关于回答问题,而不是为框架争执。感谢您的提醒。
colefner '18 -10-29

Answers:


1427

带有钩子的React Router v5.1.0

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

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

反应路由器v4

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

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

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

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

在早期版本的阵营路由器,你必须创建自己的history实例,但在第4版的<BrowserRouter><HashRouter><MemoryRouter>组件将创建一个浏览器,哈希和内存的实例为您服务。React Router history通过router对象下的上下文使与路由器关联的实例的属性和方法可用。

1.使用withRouter高阶成分

withRouter高次成分将注入的history对象作为所述部件的支柱。这样一来,您无需处理即可访问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.使用合成并渲染 <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的上下文模型感到满意时才应使用的选项(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是最简单的实现方法,因此对于大多数用例来说,它们是最好的选择。


24
我试图通过Router(({{history})=> {console.log(“ hhhhhhhhh”); history.push('/ bets')})以这种方式使用方法1。但它从未与路由器4配合使用
Dmitry Malugin

57
什么!?我可以使用withRouter而不是history遍历所有组件?我需要花更多的时间阅读文档……
hellojeffhall

18
如何在history.push('/new-location')不将该行为附加到Button或其他DOM元素的情况下直接运行?
尼尔

4
Unexpected use of 'history' no-restricted-globals
引发

18
context从反应16开始不再是实验性的
。– trysis

920

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不存在<Route>。您应该使用<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')

进一步阅读: 历史导航


React-Router 1.xx答案

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

关于此问题的主要更改是从导航混合到历史的更改。现在,它使用浏览器的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 (<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

注:如果您使用的终极版,有一个名为另一个项目 ReactRouter,终极版,为您提供终极版绑定ReactRouter,有些使用了同样的方法 做出反应,终极版

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>

3
我正在使用,v2.4.0但是提到的方法对我不起作用,我的应用程序完全无法渲染,控制台输出:Uncaught TypeError: (0 , _reactRouter.withRouter) is not a function这是指向我的SO帖子的链接:stackoverflow.com/questions/37306166/…–
nburk

7
这应该是被接受的答案,被接受的答案有点混乱并且非常古老。@GiantElk我可以按照版本答案中的描述进行操作2.6.0
JMac

2
这种方法仍然是版本推荐的方法3.0.x吗?许多人似乎使用这种context方式。
velop

6
在4.0中,this.props.history不存在。到底是怎么回事?
Nicolas S.Xu

4
this.props.history如果您的组件不是由呈现的,则@ NicolasS.Xu 不存在<Route>。您应该使用<Route path="..." component={YourComponent}/>this.props.historyYourComponent
vogdb

508

React-路由器v2

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

相关摘录:

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

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

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

它还提供了功能,pushState但已记录的警告已弃用该功能。

如果使用react-router-redux,它提供了push可以像这样分派的功能:

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

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


15
不要忘记,较新的API不使用import { browserHistory } from './react-router',而是使用创建历史记录import createBrowserHistory from 'history/lib/createBrowserHistory'。稍后,您可以history从组件props中访问:this.props.history('/some/path')
Ricardo Pedroni

7
var browserHistory = require('react-router').browserHistory; browserHistory.goBack();
鲍比

7
react-router-redux push仅更改URL,实际上不更改页面。两者都做,进口browserHistoryreact-router和使用browserHistory.push('/my-cool-path')。不幸的是,这不是很容易找到。github.com/reactjs/react-router/blob/master/docs/guides/...
安德鲁萨穆埃尔森

4
我正在使用this.props.history.push('/'),但只有URL发生了更改……这里没有实际的路由。我想念什么?
rgcalsaverini


56

这里是你如何做到这一点react-router v2.0.0ES6react-router已经摆脱了mixin。

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
我相信当前的建议是使用history@Bobby所说的单例。您可以使用,context.router但实际上很难对这些组件进行单元测试,因为实例化该组件将不会在上下文中具有此功能。
乔治·莫尔

2
@GeorgeMauer我认为这取决于代码在哪里运行。根据react docs,如果context.router在服务器上运行,则建议使用它。github.com/reactjs/react-router/blob/master/upgrade-guides/…–
KumarM

50

React-Router 4.x回答:

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

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

您需要安装历史记录,即使用的库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>;
    }
}

编辑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 <a href="#" onClick={this.navigate}>Previous</a>;
    }
}

2
除了React Router文档告诉我们,在大多数情况下,您不需要使用Router代替BrowserRouter。为您BrowserRouter创建和维护history对象。仅当您[“需要与Redux之类的状态管理工具进行深度集成”时,您才应该默认创建自己的应用程序。] reacttraining.com/react-router/web/api/Router
bobbyz

2
这是我从时间和经验中学到的东西。虽然使用默认值通常是一个好习惯this.props.history,但是我还没有找到一种解决方案可以帮助我在不是组件或未构建为React组件的任何其他工具的类中执行此操作您可以传递道具。感谢您的反馈:)
Eric Martin

44

为此,谁不控制服务器端,因此使用哈希路由器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((
  <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()
  }
})

1
谢谢。也许我想念一些东西。这与前两个答案不完全相同吗?
乔治·莫尔

2
当您使用“哈希”导航时,在“反应路由器” v2中,您需要安装其他模块“历史”(如果要避免奇怪的哈希查询),而不是使用browserHistory,则需要使用useRouterHistory(createHashHistory)( {queryKey:false})。这是我发布此消息的主要原因。我展示了如何浏览哈希历史记录。
Alexey Volodko

1
哦,我知道了,你是对的。我现在不在那个项目上,但是我认为首选的方法是history现在使用这两种方法
George Mauer

4
为什么这个答案不是最好的?为什么要使用Context或HOC或事件原型来解决所有麻烦,为什么不导入历史记录并在我们喜欢的任何地方使用呢?只是想了解权衡问题
–storm_buster

@storm_buster没有权衡。我们有ES6模块,应该使用它们!这是使用您的工具(在这种情况下反应)来完成所有事情的典型展示,甚至是您确实不想使用它们的东西。
卡帕杰

40

反应路由器V4

tl:dr;

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

简单和声明性的答案是,您需要<Redirect to={URL} push={boolean} />结合使用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 <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

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

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


这是我找到的最佳答案。withRouter在重新载入的路线上时,使用不起作用。在我们的情况下,我们必须有选择地要么做setState(导致return <Redirect>)(如果已经在路线上),要么history.push()从其他地方做。
karmakaze '18 -10-1

非常非常聪明。而且非常简单。Tks。我要在ReactRouterTable中使用它,因为我想处理整行的点击。在onRowClick上使用以设置状态。setState({navigateTo:“ / path /” + row.uuid});
罗瓦托

这是防弹的答案。
Nitin Jadhav

31

警告:此答案仅涵盖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在类上定义,否则无法访问。

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


26

在正常工作之前,我尝试了至少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中,<Link>组件本身正在使用router.push,因此您可以通过传递<Link to=标签的任何内容,例如:

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

1
它完全正常。但是响应200 OK而不是30x代码。如何解决此问题?
穆罕默德·阿泰克·阿扎姆

1
不确定。对于我来说,这从来没有出现过,因为它不是外部请求-只是您的浏览器使用页面自己的代码来更改页面上的内容。如果愿意,您始终可以执行手动javascript重定向。
本·惠勒

1
它也可以与@withRouter一起用作类装饰器...与mobx一起使用非常好
Dan

21

要以编程方式进行导航,您需要在的props.history中添加新的历史记录,这样可以为您完成工作:component

//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的版本
Ash

19

对于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 <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'));

19

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

在下面的渲染组件中,例如LoginPagerouter对象是可访问的,只需调用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<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')
);


1
为什么不与Router和browserHistory一起使用?
欧文·梅耶

1
@Erwin API在v4中有所不同。看到这个github.com/ReactTraining/react-router/issues/3847
mcku

1
@mcku您从哪里获得了react-router v4的打字稿dts文件?
jmathew '16

1
@jmathew我没有对react-router v4的任何类型定义
mcku

16

React-Router v4 ES6中

您可以使用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);

2
已经在其他几个答案中提到过(包括最上面的答案中的详细信息)
George Mauer

13

withRouter与基于类的组件一起使用,请尝试以下类似方法。不要忘记将export语句更改为使用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);

11

基于
何塞·安东尼奥·波斯蒂戈(JoséAntonio Postigo)和本·惠勒(Ben Wheeler)
的先前回答,是否具有新颖性?用Typescript编写,
并使用装饰器
静态属性/字段

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 /反应路由器”:“ ^ 2.0.41”


11

随着即将推出的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是一个示例应用程序,显示了如何使用/更新react-router,并包含导航该应用程序的示例功能测试。


5
尽管我想知道如何从生命周期挂钩或redux之类的内容进行导航,这对于从render函数进行导航非常有用。
鲁宾·马丁内斯(Ruben Martinez),

11

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

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

第二

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

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

与路由器


谢谢!!最佳答案
Taha Farooqui

9

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

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

2
hashHistory.push,赋予“无法读取”未定义的属性“ push”。您从哪里导入这些?
ArchNoob

从“反应路由器”导入{hashHistory};您可以在顶部以这种方式导入它。
Zaman Afzal

我正在从redux saga文件中使用您的代码示例,就像您说的那样使用和导入它,但我一直收到该TypeError。
ArchNoob

8

对于当前的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;

1
这适用于V4。好吧...关闭...它实际上需要是this.context.router.history.push('/ back-location');
velohomme'4


5

那些在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 re-render Test component

感谢此评论: ReactTraining问题评论


4

如果碰巧通过react-router-redux将RR4与redux配对,也可以使用from的路由动作创建者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挂钩以响应组件。


1
react-router-redux已弃用/存档很长时间了
oligofren

4

您还可以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


1
打个好电话,你能注意一下哪个版本的react-router和react指的是什么?这是一个并非总是可用的新更改
George Mauer

3

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

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

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

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

别忘了导入PropTypes

import PropTypes from 'prop-types';

请写下react-router的版本,以及您从react-router导入了什么
Ash

什么也没导入,这是版本“ react-router”:“ ^ 4.2.0”
网站管理员

3

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

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组件中可能不需要DOM。

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


您能解释为什么您会在公认的解决方案上使用它吗?
乔治·莫尔

它只是所讨论问题的替代解决方案。如前所述,这不是理想的选择,但它对于程序重定向非常有用。
neatsu

2

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

<input 
  type="button" 
  name="back" 
  id="back" 
  class="btn btn-primary" 
  value="Back" 
  onClick={() => { this.props.history.goBack() }} 
/>

当然,这需要特殊的导入-您的组件本身并没有history添加props。这来自一个HoC,您需要先导入才能使用(直接发送给Route该中心的组件会由该HoC自动包装,但是您需要导入Route...)
George Mauer

2

改用hookrouter,这是react-router的现代替代品

https://www.npmjs.com/package/hookrouter

import { useRoutes, usePath, A} from "hookrouter";

回答关于通过选择框链接的问题,您可以执行以下操作:

navigate('/about');

仅供参考。作者本人称该图书馆为“概念证明”,并且近一年没有活动(2019年6月)。
MEMark

@MEMark那是因为它已经完美了
StefanBob

好吧,否则,说38个未解决的问题以及2.0版将完全被作者重写的事实。
MEMark

1

对于React Router v4 +

假设您不需要在初始渲染本身期间进行导航(可以使用 <Redirect> component)中,这就是我们在应用程序中所做的。

定义一个返回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 (
    <HashRouter hashType="noslash">
      <Route
        render={({ history }) => {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    </HashRouter>
  );
}

1

react-router-dom:5.1.2

  • 这个站点有3个页面,所有页面都在浏览器中动态呈现。

  • 尽管该页面永远不会刷新,但是请注意当您浏览站点时,React Router如何使URL保持最新。这样可以保留浏览器的历史记录,确保后退按钮和书签之类的内容正常运行

  • 一个开关看起来通过其所有的子元素,并呈现第一个其路径当前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>
  );
}```

欢迎来到SO!当您回答的问题有很多答案时,请尝试显示您的好处。
DavidGarcíaBodego,

这也不能回答问题,即如何从命令式JS(而不是标记)中以编程方式进行操作。
乔治·莫尔

1

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

使用以下版本:

反应: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>

文档有关<HashRouter>

一个<Router>使用该URL(即哈希部分window.location.hash),以确保您的UI同步与URL。

解决方案:

  1. 使用<Redirect>使用推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 commiting 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)一样。

  1. 使用useHistory钩子:

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

let history = useHistory();

return <button onClick={() => { history.push('/usehistory') }}>
    useHistory redirect
</button>

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

  1. 使用withRouter,得到了history来自props

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

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

    return <button onClick={() => { history.push('/withrouter') }}>
        withRouter redirect
    </button>
}

export default withRouter(WithRouterAction);

withRouter文档中读取:

您可以通过高阶组件访问history对象的属性和最接近<Route>的匹配项withRouterwithRouter将通更新matchlocationhistory道具给被包装的成分时,它呈现。

演示:

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

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

我希望这有帮助!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.