react-router返回页面如何配置历史记录?


121

谁能告诉我如何返回上一页而不是特定路线?

使用此代码时:

var BackButton = React.createClass({

 mixins: [Router.Navigation],
  render: function() {
    return (
        <button
            className="button icon-left"
            onClick={this.navigateBack}>
            Back
        </button>
    );
  },

  navigateBack: function(){
    this.goBack();
  }
});

收到此错误,因为没有路由器历史记录所以goBack()被忽略了

这是我的路线:

// Routing Components
Route = Router.Route;
RouteHandler = Router.RouteHandler;
DefaultRoute = Router.DefaultRoute;

var routes = (
 <Route name="app" path="/" handler={OurSchoolsApp}>
     <DefaultRoute name="home" handler={HomePage} />
     <Route name="add-school" handler={AddSchoolPage}  />
     <Route name="calendar" handler={CalendarPage}  />
     <Route name="calendar-detail" path="calendar-detail/:id" handler={CalendarDetailPage} />
     <Route name="info-detail" path="info-detail/:id" handler={InfoDetailPage} />
     <Route name="info" handler={InfoPage} />
     <Route name="news" handler={NewsListPage} />
     <Route name="news-detail" path="news-detail/:id" handler={NewsDetailPage} />
     <Route name="contacts" handler={ContactPage} />
     <Route name="contact-detail" handler={ContactDetailPage} />
     <Route name="settings" handler={SettingsPage} />
 </Route>
 );

 Router.run(routes, function(Handler){
   var mountNode = document.getElementById('app');
   React.render(<Handler /> , mountNode);
 });

如果您找到了解决方案,请在这里分享。谢谢。
user261002

Answers:


43

我想你只需要通过intializing它就像你的路由器上启用BrowserHistory: <Router history={new BrowserHistory}>

在此之前,您应该需要BrowserHistory'react-router/lib/BrowserHistory'

希望对您有所帮助!

UPDATE:ES6中的示例

const BrowserHistory = require('react-router/lib/BrowserHistory').default;

const App = React.createClass({
    render: () => {
        return (
            <div><button onClick={BrowserHistory.goBack}>Go Back</button></div>
        );
    }
});

React.render((
    <Router history={BrowserHistory}>
        <Route path="/" component={App} />
    </Router>
), document.body);

嗨,我们面临着同样的问题。您能否详细解释一下。谢谢
user261002 2015年

23
这是正确的答案吗?这甚至无法回答问题。@bomber
GN。

14
对于任何阅读此书的人。如果要从子组件执行此操作。您可以在找到历史对象this.props.history。因此,代码变成this.props.history.goBack
Sisir

3
反应路由器4怎么样?我认为它不再支持BrowserHistory。
Akshay Lokur '17

1
从react-router-dom版本5开始,历史记录由BrowserRouter隐式创建,并且可以通过props获取,您可以通过props.history访问它。
Srikanth Kyatham '19

97

使用React v16和ReactRouter v4.2.0更新(2017年10月):

class BackButton extends Component {
  static contextTypes = {
    router: () => true, // replace with PropTypes.object if you use them
  }

  render() {
    return (
      <button
        className="button icon-left"
        onClick={this.context.router.history.goBack}>
          Back
      </button>
    )
  }
}

使用React v15和ReactRouter v3.0.0更新(2016年8月):

var browserHistory = ReactRouter.browserHistory;

var BackButton = React.createClass({
  render: function() {
    return (
      <button
        className="button icon-left"
        onClick={browserHistory.goBack}>
        Back
      </button>
    );
  }
});

用嵌入式iframe创建了一个带有一些更复杂示例的小提琴:https//jsfiddle.net/kwg1da3a/

React v14和ReacRouter v1.0.0(2015年9月10日)

你可以这样做:

var React = require("react");
var Router = require("react-router");

var SomePage = React.createClass({
  ...

  contextTypes: {
    router: React.PropTypes.func
  },
  ...

  handleClose: function () {
    if (Router.History.length > 1) {
      // this will take you back if there is history
      Router.History.back();
    } else {
      // this will take you to the parent route if there is no history,
      // but unfortunately also add it as a new route
      var currentRoutes = this.context.router.getCurrentRoutes();
      var routeName = currentRoutes[currentRoutes.length - 2].name;
      this.context.router.transitionTo(routeName);
    }
  },
  ...

您需要小心,以确保有必要的历史记录才能返回。如果您直接点击该页面,然后再点击该页面,它将带您回到浏览器历史记录中,而不是应用程序。

此解决方案将同时考虑这两种情况。但是,它将无法使用后退按钮处理可在页面内导航(并添加到浏览器历史记录)的iframe。坦白说,我认为这是react-router中的错误。在此处创建的问题:https//github.com/rackt/react-router/issues/1874


如果有一种方法可以不使用上下文就可以了?
亚当D

1
另外,根据设置,可能会使用this.props.history.goBack而不是this.context.router.history.goBack
PhoenixB '18

54
  1. 进口 withRouter

    import { withRouter } from 'react-router-dom';
  2. 将组件导出为:

    export withRouter(nameofcomponent) 
  3. 例如,单击按钮时,调用goBack

    <button onClick={this.props.history.goBack}>Back</button>

react-router-domv4.3上测试


2
顺便说一句,即使没有导入或使用,它也对我有用withRouter。也许我们只是在使用浏览器历史记录本机API。但是可以吗?
Gianfranco P.

1
那是很好的解决方案。用户使用直接URL登陆到页面时的唯一问题->由于它没有历史记录,因此会破坏应用程序。
skryvets

2
最好的解释在这里
Z_z_Z

@MichaelFreidgeim您能否上传代码段,以便我进行检查和验证
gaurav makwana,


32

ES6方法没有使用反应路由器的无混合功能的无状态功能。

import React from 'react'
import { browserHistory } from 'react-router'

export const Test = () => (
  <div className="">
    <button onClick={browserHistory.goBack}>Back</button>
  </div>
)

3
尝试您的解决方案时,我收到浏览器警告:export 'browserHistory' was not found in 'react-router'
拉尔夫·大卫·阿伯纳西

2
browserHistory仅存在于v2和v3中。如果使用v4,则应阅读迁移指南:github.com/ReactTraining/react-router/blob/…–
ptorsson

@Ralp,如果您收到此错误信息,检查了这一点:stackoverflow.com/questions/49787659/...
万里M.

13

使用React挂钩

进口:

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

在无状态组件中:

  let history = useHistory();

活动中

history.goBack()

<button onClick = {()=> history.goBack()}>返回</ button>
Hunter

感谢您提及这一点,因为我喜欢钩子。到目前为止,我一直在使用withRouter。
纽曼

10

使用React 16.0和React-router v4 Live Example来检查我的工作示例。查看代码Github

使用withRouterhistory.goBack()

这就是我正在实施的想法...

History.js

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom'
import './App.css'


class History extends Component {

  handleBack = () => {
    this.props.history.goBack()
  }

  handleForward = () => {
    console.log(this.props.history)
    this.props.history.go(+1)
  }

  render() {
    return <div className="container">
      <div className="row d-flex justify-content-between">
        <span onClick={this.handleBack} className="d-flex justify-content-start button">
          <i className="fas fa-arrow-alt-circle-left fa-5x"></i>
        </span>
        <span onClick={this.handleForward} className="d-flex justify-content-end button">
          <i className="fas fa-arrow-alt-circle-right fa-5x"></i>
        </span>
      </div>
    </div>
  }
}

export default withRouter(History)

PageOne.js

import React, { Fragment, Component } from 'react'

class PageOne extends Component {

   componentDidMount(){
      if(this.props.location.state && this.props.location.state.from != '/pageone')
      this.props.history.push({
         pathname: '/pageone',
         state: { 
             from: this.props.location.pathname
         }
       });
   }

   render() {
      return (
         <Fragment>
            <div className="container-fluid">
               <div className="row d-flex justify-content-center">
                  <h2>Page One</h2>
               </div>
            </div>
         </Fragment>
      )
   }
}

export default PageOne

ps抱歉,代码太大,无法在此处发布所有内容


1
自19年代起,这应该是公认的答案。React Router提供了一个称为“ withRouter”的高阶组件(HOC),因此您可以包装您的组件以访问道具,例如历史记录和位置。

1
是的,如包装您的组件中HOC中的withRouter一样,将提供历史记录和位置数据。没有挑战,就不会读书,也永远不会安定下来。
阿努帕姆·毛里雅

我可能会问,为什么你通过加号go功能:history.go(+1)history.go(1)应该足够了。
gion_13 '19

10

这适用于浏览器和哈希历史记录。

this.props.history.goBack();

8

这是一个正常工作的BackButton组件(反应0.14):

var React = require('react');
var Router = require('react-router');

var History = Router.History;

var BackButton = React.createClass({
  mixins: [ History ],
  render: function() {
    return (
      <button className="back" onClick={this.history.goBack}>{this.props.children}</button>
    );
  }
});

module.exports = BackButton;

如果没有历史记录,您当然可以执行以下操作:

<button className="back" onClick={goBack}>{this.props.children}</button>

function goBack(e) {
  if (/* no history */) {
    e.preventDefault();
  } else {
    this.history.goBack();
  }
}

7

对于react-router v2.x,这已更改。这是我为ES6做的事情:

import React from 'react';
import FontAwesome from 'react-fontawesome';
import { Router, RouterContext, Link, browserHistory } from 'react-router';

export default class Header extends React.Component {

  render() {
    return (
      <div id="header">
        <div className="header-left">
          {
            this.props.hasBackButton &&
            <FontAwesome name="angle-left" className="back-button" onClick={this.context.router.goBack} />
          }
        </div>
        <div>{this.props.title}</div>
      </div>
    )
  }
}

Header.contextTypes = {
  router: React.PropTypes.object
};

Header.defaultProps = {
  hasBackButton: true
};

Header.propTypes = {
  title: React.PropTypes.string
};

5

在react-router v4.x中,您可以使用history.goBack等效于history.go(-1)

App.js

import React from "react";
import { render } from "react-dom";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contact from "./Contact";
import Back from "./Back";

const styles = {
  fontFamily: "sans-serif",
  textAlign: "left"
};

const App = () => (
  <div style={styles}>
    <Router>
      <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/about">About</Link></li>
          <li><Link to="/contact">Contact</Link></li>
        </ul>

        <hr />

        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />

        <Back />{/* <----- This is component that will render Back button */}
      </div>
    </Router>
  </div>
);

render(<App />, document.getElementById("root"));

Back.js

import React from "react";
import { withRouter } from "react-router-dom";

const Back = ({ history }) => (
  <button onClick={history.goBack}>Back to previous page</button>
);

export default withRouter(Back);

演示: https //codesandbox.io/s/ywmvp95wpj

请记住,使用history用户可以离开,因为history.goBack()可以在打开您的应用程序之前加载访问者访问过的页面。


为了避免上述情况,我创建了一个简单的库react-router-last-location,用于监视用户的最后位置。

用法非常简单。首先,你需要安装react-router-domreact-router-last-locationnpm

npm install react-router-dom react-router-last-location --save

然后使用LastLocationProvider如下:

App.js

import React from "react";
import { render } from "react-dom";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { LastLocationProvider } from "react-router-last-location";
//              ↑
//              |
//              |
//
//       Import provider
//
import Home from "./Home";
import About from "./About";
import Contact from "./Contact";
import Back from "./Back";

const styles = {
  fontFamily: "sans-serif",
  textAlign: "left"
};

const App = () => (
  <div style={styles}>
    <h5>Click on About to see your last location</h5>
    <Router>
      <LastLocationProvider>{/* <---- Put provider inside <Router> */}
        <div>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/contact">Contact</Link></li>
          </ul>

          <hr />

          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />

          <Back />
        </div>
      </LastLocationProvider>
    </Router>
  </div>
);

render(<App />, document.getElementById("root"));

Back.js

import React from "react";
import { Link } from "react-router-dom";
import { withLastLocation } from "react-router-last-location";
//              ↑
//              |
//              |
//
//    `withLastLocation` higher order component
//    will pass `lastLocation` to your component               
//
//                   |
//                   |
//                   ↓
const Back = ({ lastLocation }) => (
  lastLocation && <Link to={lastLocation || '/'}>Back to previous page</Link>
);


//          Remember to wrap
//   your component before exporting
//
//                   |
//                   |
//                   ↓
export default withLastLocation(Back);

演示: https : //codesandbox.io/s/727nqm99jj


您如何将LastLocation对象插入需要它的组件中-也就是说,我想以编程方式使用它,而不是像您的示例那样在某些显示的输出中使用:if(lastLocation =='about')
dmayo

不知道我是否正确地理解了你,所以如果我错了,请纠正我。您是否想lastLocation在React之外使用,或者说I'd like to use it programmatically,您是否想像导入一样import { lastLocation } from '...'
hinok

5

对我有用的是在文件顶部使用Router导入。

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

然后使用它将导出的函数包装在文件的底部;

export default withRouter(WebSitePageTitleComponent)

然后,我可以访问路由器的历史记录道具。完整的示例代码如下!

import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'

import PropTypes from 'prop-types'

class TestComponent extends Component {
  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    event.preventDefault()
    this.props.history.goBack()
  }

  render() {
    return (
      <div className="page-title">
        <a className="container" href="/location" onClick={this.handleClick}>
          <h1 className="page-header">
            { this.props.title }
          </h1>
        </a>
      </div>
    )
  }
}

const { string, object } = PropTypes

TestComponent.propTypes = {
  title: string.isRequired,
  history: object
}

export default withRouter(TestComponent)

5

返回特定页面

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

  const history = useHistory();
  
  const routeChange = () => {
    let path = '/login';
    history.push(path);
  };

返回上一页

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

  const history = useHistory();
  
  const routeChange = () => {
    history.goBack()
  };

2
谢谢,这是一个很棒的2020年答案!公认的答案是这样的2015
。– Beetosino

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

this.props.history.goBack();

我正在使用这些版本

"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",

2

对我有用的唯一解决方案是最简单的。无需其他进口。

<a href="#" onClick={() => this.props.history.goBack()}>Back</a>

IamTks,Mussain


非常好。简单而谦虚
Dinesh Kanivu

1

像这样调用以下组件:

<BackButton history={this.props.history} />

这是组件:

import React, { Component } from 'react'
import PropTypes from 'prop-types'
class BackButton extends Component {
  constructor() {
    super(...arguments)

    this.goBack = this.goBack.bind(this)
  }

  render() {
    return (
      <button
        onClick={this.goBack}>
          Back
      </button>
    )
  }

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

BackButton.propTypes = {
  history: PropTypes.object,
}

export default BackButton

我正在使用:

"react": "15.6.1"
"react-router": "4.2.0"

1

REDUX

您也可以使用react-router-reduxhas goBack()push()

这是一个采样器包:

在应用程序的入口点,您需要ConnectedRouter,并且有时要进行棘手的连接是history对象。Redux中间件监听历史更改:

import React from 'react'
import { render } from 'react-dom'
import { ApolloProvider } from 'react-apollo'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import client from './components/apolloClient'
import store, { history } from './store'
import Routes from './Routes'
import './index.css'

render(
  <ApolloProvider client={client}>
    <Provider store={store}>
      <ConnectedRouter history={history}>
        <Routes />
      </ConnectedRouter>
    </Provider>
  </ApolloProvider>,
  document.getElementById('root'),
)

我将向您展示一种连接方式history。请注意,历史记录如何导入到商店中以及如何作为单例导出,以便可以在应用程序的入口点使用:

import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from './reducers'

export const history = createHistory()

const initialState = {}
const enhancers = []
const middleware = [thunk, routerMiddleware(history)]

if (process.env.NODE_ENV === 'development') {
  const { devToolsExtension } = window
  if (typeof devToolsExtension === 'function') {
    enhancers.push(devToolsExtension())
  }
}

const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers)
const store = createStore(rootReducer, initialState, composedEnhancers)

export default store

上面的示例块显示了如何加载react-router-redux完成设置过程的中间件帮助程序。

我认为这下一部分是完全多余的,但是我将包括其中,以防将来有人从中受益:

import { combineReducers } from 'redux'
import { routerReducer as routing } from 'react-router-redux'

export default combineReducers({
  routing, form,
})

我一直使用routerReducer它,因为它可以强制重新加载通常由于而不需要的组件shouldComponentUpdate。最明显的例子是您拥有一个导航栏,该导航栏应该在用户按下NavLink按钮时更新。如果走那条路,您将了解Redux的connect方法使用shouldComponentUpdate。使用routerReducer,您可以mapStateToProps将路线更改映射到导航栏中,这将触发它在历史对象更改时进行更新。

像这样:

const mapStateToProps = ({ routing }) => ({ routing })

export default connect(mapStateToProps)(Nav)

请原谅我,当时我为人们添加了一些额外的关键字:如果您的组件更新不正确,请shouldComponentUpdate通过删除connect函数进行调查,看看它是否可以解决问题。如果是这样,请拉入routerReducer,URL更改时组件将正确更新。

最后,完成所有操作后,您可以随时致电goBack()或致电push()

现在尝试使用一些随机组件:

  1. 汇入 connect()
  2. 您甚至不需要mapStateToPropsmapDispatchToProps
  3. 导入goBack并从中推送 react-router-redux
  4. 呼叫 this.props.dispatch(goBack())
  5. 呼叫 this.props.dispatch(push('/sandwich'))
  6. 体验积极的情绪

如果您需要更多采样,请查看:https : //www.npmjs.com/package/react-router-redux



0

这段代码将为您解决问题。

this.context.router.history.goBack()

0

反应路由器v6

useNavigate 钩子是现在返回的推荐方法:

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

function App() {
  const navigate = useNavigate();

  return (
    <>
      <button onClick={() => navigate(-1)}>go back</button>
      <button onClick={() => navigate(1)}>go forward</button>
    </>
  );
}

Codesandbox示例

返回/转发多个历史记录堆栈条目:
<button onClick={() => navigate(-2)}>go two back</button>
<button onClick={() => navigate(2)}>go two forward</button>
转到特定路线:
navigate("users") // go to users route, like history.push
navigate("users", { replace: true }) // go to users route, like history.replace
navigate("users", { state }) // go to users route, pass some state in

useNavigate 替换 useHistory以更好地支持即将到来的React Suspense / Concurrent模式。


我尝试尝试执行此操作,但出现错误:Attempted import error: 'useNavigate' is not exported from 'react-router-dom'.
Geek

1
@Geek好收获。使用v6.0.0-beta.0,开发人员已使history软件包成为对等依赖项。看一下更新的Codesandbox,它现在可以再次使用。
ford04

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.