react-router wróć do strony Jak konfigurujesz historię?

121

Czy ktoś może mi powiedzieć, jak mogę wrócić do poprzedniej strony zamiast określonej trasy?

Używając tego kodu:

var BackButton = React.createClass({

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

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

Pobierz ten błąd, goBack () został zignorowany, ponieważ nie ma historii routera

Oto moje trasy:

// 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);
 });
Bombowiec
źródło
jeśli znalazłeś rozwiązanie, czy możesz, proszę, udostępnij je tutaj. dzięki.
user261002

Odpowiedzi:

43

Myślę, że po prostu trzeba włączyć BrowserHistory na routerze przez intializing to tak: <Router history={new BrowserHistory}>.

Wcześniej powinieneś wymagać BrowserHistory od'react-router/lib/BrowserHistory'

Mam nadzieję że to pomogło !

UPDATE: przykład w 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);
Ghislaindj
źródło
cześć, mamy ten sam problem. czy mógłbyś wyjaśnić bardziej szczegółowo. DZIĘKI
user261002
23
Jak to jest poprawna odpowiedź? To nawet nie odpowiada na pytanie. @bomber
GN.
14
Dla każdego, kto to czyta. Jeśli chcesz to zrobić z komponentu podrzędnego. Obiekt historii można znaleźć pod adresem this.props.history. Tak więc kod staje sięthis.props.history.goBack
Sisir
3
A co z React-routerem 4? Myślę, że nie obsługuje już BrowserHistory.
Akshay Lokur
1
Od wersji 5reak-router-dom historia jest tworzona niejawnie przez BrowserRouter i jest dostępna za pośrednictwem właściwości, do której można uzyskać dostęp poprzez props.history.
Srikanth Kyatham
97

Aktualizacja za pomocą React v16 i ReactRouter v4.2.0 (październik 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>
    )
  }
}

Aktualizacja za pomocą React v15 i ReactRouter v3.0.0 (sierpień 2016):

var browserHistory = ReactRouter.browserHistory;

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

Utworzono skrzypce z nieco bardziej złożonym przykładem z osadzonym iframe: https://jsfiddle.net/kwg1da3a/

React v14 i ReacRouter v1.0.0 (10 września 2015)

Możesz to zrobić:

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

Musisz uważać, aby mieć historię niezbędną do powrotu. Jeśli wejdziesz na stronę bezpośrednio, a następnie wrócisz, przeniesie Cię z powrotem do historii przeglądarki przed aplikacją.

To rozwiązanie zajmie się obydwoma scenariuszami. Nie będzie jednak obsługiwać elementu iframe, który może poruszać się po stronie (i dodawać do historii przeglądarki) za pomocą przycisku Wstecz. Szczerze mówiąc, myślę, że to błąd w routerze reagującym. Problem utworzono tutaj: https://github.com/rackt/react-router/issues/1874

mlunoe
źródło
Byłoby miło, gdyby istniał sposób na zrobienie tego bez użycia kontekstu?
Adam D
1
Ponadto, w zależności od konfiguracji, może używać this.props.history.goBack zamiast this.context.router.history.goBack
PhoenixB
54
  1. import withRouter

    import { withRouter } from 'react-router-dom';
  2. Wyeksportuj swój komponent jako:

    export withRouter(nameofcomponent) 
  3. Przykład, po kliknięciu przycisku zadzwoń goBack:

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

Testowane w wersji react-router-dom4.3

gaurav makwana
źródło
2
BTW działa u mnie nawet bez importowania lub używania withRouter. Może po prostu używamy natywnego interfejsu API historii przeglądarki. Ale czy to w porządku?
Gianfranco P.
1
To fajne rozwiązanie. Jedyny problem, gdy użytkownik wyląduje na stronie za pomocą bezpośredniego adresu URL -> zepsuje aplikację, ponieważ nie ma historii.
skryvets
2
Najlepsze wyjaśnienie tutaj
Z_z_Z
@MichaelFreidgeim, czy możesz przesłać fragment kodu, abym go sprawdził i zweryfikował
gaurav makwana
43
this.context.router.goBack()

Nie wymaga połączenia nawigacji!

ahhhhhhhhhhhhhhhhhhhhhhhhhhhhh
źródło
1
To nadal działa w React Router v4, ale tak jest this.context.router.history.goBack. (+ historia)
Ben Gotow
13
Zreak-router-dom: "v4.2.2" i import { withRouter } from 'react-router-dom';współpracuje zthis.props.history.goBack();
felansu
1
oprócz komentarza @ felansu musisz również wyeksportować swój komponent za pomocą routera, jak wyjaśniono w odpowiedzi stackoverflow.com/a/49130220/3123338
Mister Q
32

Metoda ES6 bez mikserów z wykorzystaniem routera reagującego, funkcja bezstanowa.

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

export const Test = () => (
  <div className="">
    <button onClick={browserHistory.goBack}>Back</button>
  </div>
)
ptorsson
źródło
3
Podczas wypróbowywania twojego rozwiązania pojawia się ostrzeżenie przeglądarki:export 'browserHistory' was not found in 'react-router'
Ralph David Abernathy
2
browserHistory istnieje tylko w wersji 2 i 3. Jeśli używasz wersji 4, przeczytaj przewodnik migracji: github.com/ReactTraining/react-router/blob/ ...
ptorsson
@Ralp, jeśli pojawi się ten komunikat o błędzie, sprawdź to: stackoverflow.com/questions/49787659/ ...
Miles M.
13

Używanie haków React

Import:

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

W komponencie bezstanowym:

  let history = useHistory();

Na wydarzeniu

history.goBack()
Eric Roberto
źródło
<button onClick = {() => history.goBack ()}> Wstecz </button>
Hunter
Dzięki za wspomnienie o tym, bo lubię haczyki. Do tej pory korzystałem z withRouter.
newman
10

Sprawdź mój przykład roboczy przy użyciu React 16.0 z React-router v4 Live Example . sprawdź kod Github

Posługiwać się withRouter ihistory.goBack()

To jest idea, którą wdrażam ...

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 przepraszam, że kod jest za duży, aby opublikować wszystko tutaj

Morris S
źródło
1
To powinna być akceptowana odpowiedź na rok 19. React Router dostarcza komponent wyższego rzędu (HOC) o nazwie "withRouter", dzięki czemu można opakować komponent, aby mieć dostęp do właściwości, takich jak historia i lokalizacja.
1
tak jak withRouter w HOC podczas pakowania części składowej, zapewni historię i dane o lokalizacji. Nie ma nic trudnego do czytania i nigdy się nie osiedla.
Anupam Maurya
Czy mogę zapytać, dlaczego przekazujesz znak plus do gofunkcji history.go(+1):? history.go(1)powinno wystarczyć.
gion_13
10

Działa to z historią przeglądarki i skrótu.

this.props.history.goBack();
user3322876
źródło
8

To jest działający komponent 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;

Oczywiście możesz zrobić coś takiego, jeśli nie ma historii:

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

function goBack(e) {
  if (/* no history */) {
    e.preventDefault();
  } else {
    this.history.goBack();
  }
}
ngstschr
źródło
7

Zmieniło się to w przypadku act-router v2.x. Oto, co robię dla 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
};
aceofspades
źródło
5

W React-router v4.x możesz użyć history.goBackodpowiednika 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);

Próbny: https://codesandbox.io/s/ywmvp95wpj

Pamiętaj, że korzystając historyz usług użytkownicy mogą opuścić witrynę, ponieważ history.goBack()mogą załadować stronę, którą odwiedził odwiedzający przed otwarciem aplikacji.


Aby zapobiec takiej sytuacji jak opisana powyżej, stworzyłem prostą bibliotekę reaguj-router-ostatnia-lokalizacja która obserwuje ostatnią lokalizację użytkowników.

Użycie jest bardzo proste. Najpierw musisz zainstalować react-router-domi react-router-last-locationod npm.

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

Następnie użyj LastLocationProvider jak poniżej:

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

Demo: https://codesandbox.io/s/727nqm99jj

hinok
źródło
Jak po prostu wciągnąłbyś obiekt LastLocation do komponentu, który go potrzebuje - to znaczy, chciałbym go używać programowo, zamiast w niektórych wyświetlanych wynikach, takich jak twoje przykłady: if (lastLocation == 'about')
dmayo
Nie jestem pewien, czy dobrze Cię zrozumiałem, więc proszę, popraw mnie, jeśli się mylę. Czy chciałbyś używać lastLocationpoza Reactem, czy może mówiąc I'd like to use it programmatically, czy chcesz po prostu mieć możliwość importowania import { lastLocation } from '...'?
hinok
5

To, co zadziałało, to importowanie z routerem na początku mojego pliku;

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

Następnie użyj go do zawinięcia wyeksportowanej funkcji na dole mojego pliku;

export default withRouter(WebSitePageTitleComponent)

Dzięki temu uzyskałem dostęp do właściwości historii routera. Pełny przykładowy kod poniżej!

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)
Vancy-spodnie
źródło
5

Wróć do określonej strony :

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

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

Wróć do poprzedniej strony:

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

  const history = useHistory();
  
  const routeChange = () => {
    history.goBack()
  };
dhahn
źródło
2
dzięki, to świetna odpowiedź na rok 2020! Przyjęta odpowiedź brzmiała tak 2015.
beeftosino
3
import { withRouter } from 'react-router-dom'

this.props.history.goBack();

Używam tych wersji

"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
dush88c
źródło
2

Jedyne rozwiązanie, które działało u mnie, było najprostsze. Nie jest potrzebny dodatkowy import.

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

Tks, IamMHussain

JBarros
źródło
Bardzo dobrze. Prosty i
pokorny
1

Wywołaj następujący komponent w ten sposób:

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

A oto składnik:

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

Używam:

"react": "15.6.1"
"react-router": "4.2.0"
Gal Bracha
źródło
1

REDUX

Możesz także użyć react-router-reduxktóre ma goBack()i push().

Oto pakiet samplerów do tego:

W punkcie wejścia aplikacji potrzebujesz ConnectedRouter, a czasem trudnym do podłączenia jest historyobiekt. Oprogramowanie pośredniczące Redux nasłuchuje zmian w historii:

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'),
)

Pokażę ci sposób podłączenia history. Zwróć uwagę, jak historia jest importowana do sklepu, a także eksportowana jako singleton, dzięki czemu można jej użyć w punkcie wejścia aplikacji:

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

Powyższy przykładowy blok pokazuje, jak załadować react-router-reduxpomocników oprogramowania pośredniego, które kończą proces instalacji.

Myślę, że ta następna część jest zupełnie dodatkowa, ale dołączę ją na wypadek, gdyby ktoś w przyszłości znalazł korzyści:

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

export default combineReducers({
  routing, form,
})

Używam routerReducercały czas, ponieważ pozwala mi to wymusić przeładowanie komponentów, które normalnie nie powodują shouldComponentUpdate. Oczywistym przykładem jest pasek nawigacji, który ma się aktualizować, gdy użytkownik naciśnie NavLinkprzycisk. Jeśli pójdziesz tą drogą, dowiesz się, że metoda łączenia Redux wykorzystujeshouldComponentUpdate . Dzięki routerReducer, możesz użyćmapStateToProps mapować zmiany tras na pasku nawigacyjnym, co spowoduje jego aktualizację, gdy zmieni się obiekt historii.

Lubię to:

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

export default connect(mapStateToProps)(Nav)

Wybacz mi, dodam kilka dodatkowych słów kluczowych dla ludzi: jeśli twój komponent nie aktualizuje się prawidłowo, zbadaj shouldComponentUpdate , usuwając funkcję connect i zobacz, czy rozwiązuje problem. Jeśli tak, pobierz, routerReducera komponent zaktualizuje się poprawnie po zmianie adresu URL.

Na zakończenie, po zrobieniu tego wszystkiego, możesz zadzwonić goBack() lubpush() dowolnym momencie!

Wypróbuj teraz w jakimś losowym komponencie:

  1. Importuj w connect()
  2. Nie potrzebujesz nawet mapStateToPropslubmapDispatchToProps
  3. Importuj w goBack i wypychaj z react-router-redux
  4. Połączenie this.props.dispatch(goBack())
  5. Połączenie this.props.dispatch(push('/sandwich'))
  6. Przeżyj pozytywne emocje

Jeśli potrzebujesz więcej próbek, sprawdź: https://www.npmjs.com/package/react-router-redux

agm1984
źródło
1

Po prostu użyj w ten sposób

<span onClick={() => this.props.history.goBack()}>Back</span>
IamMHussain
źródło
0

Ten fragment kodu załatwi sprawę za Ciebie.

this.context.router.history.goBack()
prajeesh
źródło
0

React Router v6

useNavigate Hook to zalecany sposób powrotu teraz:

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

Próbka Codesandbox

Wróć / naprzód wiele wpisów na stosie historii:
<button onClick={() => navigate(-2)}>go two back</button>
<button onClick={() => navigate(2)}>go two forward</button>
Idź do określonej trasy:
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 zastępuje, useHistory aby lepiej obsługiwać nadchodzący tryb React Suspense / Concurrent.

ford04
źródło
Próbowałem tego spróbować, ale otrzymałem błąd:Attempted import error: 'useNavigate' is not exported from 'react-router-dom'.
Geek
1
@Geek dobry chwyt. Dzięki v6.0.0-beta.0programowi deweloperzy uczynili historypakiet zależnością równorzędną. Spójrz na zaktualizowaną skrzynkę Codesandbox, która znów działa.
ford04