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

якщо ви знайшли рішення, можете, будь ласка, поділитися ним тут. Дякую.
користувач261002

Відповіді:


43

Я думаю , вам просто потрібно включити 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);

привіт, ми стикаємося з тією ж проблемою. Ви можете, будь ласка, пояснити детальніше. СПАСИБО
користувач261002

23
Як це правильна відповідь? Це навіть не відповідає на питання. @bomber
GN.

14
Для всіх, хто читає це. Якщо ви хочете зробити це з дочірнього компонента. Ви можете знайти об’єкт історії за адресою this.props.history. Отже, код стаєthis.props.history.goBack
Сисір

3
Як щодо react-router 4? Я не думаю, що він більше не підтримує BrowserHistory.
Акшай Локур

1
Що стосується версії 5 реактора-маршрутизатора, історія створюється BrowserRouter неявно і доступна через реквізит, ви можете отримати доступ до неї через props.history.
Шрікант Кьятем

97

Оновлення за допомогою 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>
    );
  }
});

Створив загадку з трохи складнішим прикладом із вбудованим кадром: 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, який може переміщатися по сторінці (і додавати до історії браузера) за допомогою кнопки "назад". Чесно кажучи, я думаю, що це помилка в реакторі-маршрутизаторі. Випуск створений тут: https://github.com/rackt/react-router/isissue/1874


Було б добре, якби був спосіб зробити це без використання контексту?
Адам Д

1
Також, залежно від налаштування, можливо, ви можете використовувати this.props.history.goBack замість цього.context.router.history.goBack
PhoenixB

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
BTW працює для мене навіть без імпорту та використання withRouter. Можливо, ми просто використовуємо нативний API історії браузера. Але це нормально ??
Джанфранко П.

1
Це приємне рішення. Єдина проблема, коли користувач переходить на сторінку за допомогою прямої URL-адреси -> вона зламає додаток, оскільки у нього немає історії.
скривець

2
Найкраще тут пояснення
Z_z_Z

@MichaelFreidgeim чи можете ви, будь ласка, завантажте фрагмент коду, щоб я перевірив і перевірив
gaurav makwana

43
this.context.router.goBack()

Не потрібна навігаційна суміш!


1
Це все ще працює в React Router v4, але це так this.context.router.history.goBack. (+ історія)
Ben Gotow

13
З react-router-dom: "v4.2.2" та import { withRouter } from 'react-router-dom';працює зthis.props.history.goBack();
felansu

1
окрім коментаря @ felansu, вам також потрібно експортувати свій компонент withRouter, як пояснено у відповіді 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
Історія браузера існує лише у версіях v2 та v3. Якщо ви використовуєте v4, слід прочитати посібник з міграції: github.com/ReactTraining/react-router/blob/…
ptorsson

@Ralp, якщо ви отримаєте це повідомлення про помилку, перевірте це: stackoverflow.com/questions/49787659/…
Miles M.

13

Використання гачків React

Імпорт:

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

У складі без громадянства:

  let history = useHistory();

На Події

history.goBack()

<кнопка onClick = {() => history.goBack ()}> Назад </button>
Мисливець

Дякую, що згадуєте про це, бо мені подобаються гачки. Я до цього часу використовую withRouter.
новачок

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
Це має бути прийнята відповідь станом на 19 рік. Маршрутизатор React надає компонент вищого порядку (HOC), який називається "withRouter", щоб ви могли обгортати ваш компонент, щоб мати доступ до реквізитів, таких як історія та місцезнаходження.

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

Чи можу я запитати, чому ви передаєте знак плюс goфункції history.go(+1)? history.go(1)повинно вистачити
gion_13


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

Для реактора-маршрутизатора 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

У реакторі-маршрутизаторі 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"));

Назад.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-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"));

Назад.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 р.
beeftosino

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>

Tks, 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. Очевидний приклад - коли у вас є Nav Bar, який повинен оновлюватися, коли користувач натискає NavLinkкнопку. Якщо ви підете цією дорогою, ви дізнаєтесь, що використовується метод підключення Redux shouldComponentUpdate. З routerReducer, ви можете використовуватиmapStateToProps для відображення змін маршрутизації в Nav Bar, і це призведе до оновлення, коли зміниться об’єкт історії.

Подобається це:

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

Просто використовуйте так

<span onClick={() => this.props.history.goBack()}>Back</span>

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

Зразок коду та скриньки

Повернутися назад / вперед кілька записів стека історії:
<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, devs зробили historyпакет однорідної залежності. Погляньте на оновлений Codesandbox, який працює знову.
ford04

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.