response-router вернуться на страницу как настроить историю?


124

Кто-нибудь может сказать мне, как я могу вернуться на предыдущую страницу, а не на конкретный маршрут?

При использовании этого кода:

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

Ответы:


44

Я думаю , вам просто нужно включить BrowserHistory на маршрутизаторе по intializing это так: <Router history={new BrowserHistory}>.

Перед этим необходимо потребовать BrowserHistoryот'react-router/lib/BrowserHistory'

Надеюсь, это поможет !

ОБНОВЛЕНИЕ: пример в 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

23
Как это правильный ответ? Это даже не отвечает на вопрос. @bomber
GN.

15
Для всех, кто это читает. Если вы хотите сделать это из дочернего компонента. Вы можете найти объект истории по адресу this.props.history. Таким образом, код становитсяthis.props.history.goBack
Sisir

3
Как насчет реактивного маршрутизатора 4? Я не думаю, что он больше поддерживает BrowserHistory.
Акшай

1
Начиная с response-router-dom версии 5, история создается BrowserRouter неявно и доступна через props, вы можете получить к ней доступ через props.history.
Srikanth Kyatham

98

Обновление с React v16 и ReactRouter v4.2.0 (октябрь 2017 г.):

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 г.):

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 (10 сентября 2015 г.)

Ты можешь сделать это:

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, который может перемещаться по странице (и добавлять в историю браузера) с помощью кнопки возврата. Честно говоря, я считаю, что это ошибка в response-router. Проблема создана здесь: https://github.com/rackt/react-router/issues/1874


Было бы неплохо, если бы был способ сделать это без использования контекста?
Adam D

1
Также, в зависимости от настройки, может использоваться this.props.history.goBack вместо this.context.router.history.goBack
PhoenixB 01

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 ->, это сломает приложение, поскольку у него нет истории.
скрывец 03

2
Лучшее объяснение здесь
Z_z_Z

@MichaelFreidgeim, не могли бы вы загрузить свой фрагмент кода, чтобы я проверил и подтвердил
гаурав маквана,

43
this.context.router.goBack()

Навигационный миксин не требуется!


1
Это все еще работает в React Router v4, но это this.context.router.history.goBack. (+ история)
Бен Готоу

13
С response-router-dom: "v4.2.2" и import { withRouter } from 'react-router-dom';работает сthis.props.history.goBack();
felansu 01

1
в дополнение к комментарию @felansu вам также необходимо экспортировать свой компонент с помощью Router, как описано в ответе stackoverflow.com/a/49130220/3123338
Mister Q

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/…
Майлз М.

14

Использование React Hooks

Импортировать:

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

В компоненте без состояния:

  let history = useHistory();

По событию

history.goBack()

<button onClick = {() => history.goBack ()}> Назад </button>
Hunter

Спасибо, что упомянули об этом, потому что мне нравятся крючки. Я до сих пор использую withRouter.
Newman

10

Посмотрите мой рабочий пример с использованием React 16.0 с React-router v4 Live Example . проверьте код Github

Использование withRouterиhistory.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
Это должен быть принятый ответ с 1919 года. React Router предоставляет компонент более высокого порядка (HOC) под названием «withRouter», поэтому вы можете обернуть свой компонент, чтобы получить доступ к таким свойствам, как история и местоположение.

1
да, как в withRouter в HOC, когда вы завершаете свою компонентную часть, предоставит данные истории и местоположения. Ничего сложного продолжает читать и никогда не останавливается.
Анупам Маурья

Могу ли я спросить , почему вы передаете знак плюс к goфункции: history.go(+1)? history.go(1)должно хватить.
gion_13 05

10

Это работает с историей браузера и хеширования.

this.props.history.goBack();

8

Это рабочий компонент BackButton (React 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

Для response-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
};

6

Вернуться на конкретную страницу :

  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.
beeftosino

5

В response-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()могут загрузить страницу, которую посетитель посетил до открытия вашего приложения.


Чтобы предотвратить описанную выше ситуацию, я создал простую библиотеку response-router-last-location, которая отслеживает последнее местоположение ваших пользователей.

Использование очень простое. Для начала нужно установить react-router-domи react-router-last-locationиз npm.

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)

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>

Ткс, IamMHussain


Очень хорошо. Простой и скромный
Динеш Каниву

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-reduxкоторого есть 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 использует shouldComponentUpdate. С помощью routerReducer, вы можете использовать mapStateToPropsдля отображения изменений маршрутизации в панели навигации, и это приведет к ее обновлению при изменении объекта истории.

Как это:

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

export default connect(mapStateToProps)(Nav)

Простите меня, но я добавляю несколько дополнительных ключевых слов для людей: если ваш компонент не обновляется должным образом, исследуйте shouldComponentUpdate, удалив функцию подключения, и посмотрите, решит ли она проблему. Если это так, потяните за, routerReducerи компонент обновится должным образом при изменении URL-адреса.

В заключение, после всего этого вы можете позвонить goBack()или в push()любое время!

Попробуйте сейчас в каком-нибудь случайном компоненте:

  1. Импортировать в connect()
  2. Вам даже не нужно mapStateToPropsилиmapDispatchToProps
  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



1

React Router v6

useNavigate Hook - это рекомендуемый способ вернуться сейчас:

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

Примеры кодов и песочницы

Переход назад / вперед на несколько записей стека истории:
<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.


Я попытался это сделать, но получил ошибку:Attempted import error: 'useNavigate' is not exported from 'react-router-dom'.
Компьютерщик,

1
@ Geek хороший улов. С v6.0.0-beta.0, разработчики сделали historyпакет равноправной зависимости. Взгляните на обновленную Codesandbox, которая теперь снова работает.
ford04


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.