reagire-router tornare indietro di una pagina come si configura la cronologia?


123

Qualcuno può dirmi come posso tornare alla pagina precedente piuttosto che a un percorso specifico?

Quando si utilizza questo codice:

var BackButton = React.createClass({

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

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

Ottieni questo errore, goBack () è stato ignorato perché non c'è la cronologia del router

Ecco i miei percorsi:

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

se hai trovato una soluzione, potresti per favore condividerla qui. Grazie.
user261002

Risposte:


44

Penso che non vi resta che abilitare BrowserHistory sul router per INIZIALIZZA in quel modo: <Router history={new BrowserHistory}>.

Prima di ciò, dovresti richiedere BrowserHistoryda'react-router/lib/BrowserHistory'

Spero che aiuti !

AGGIORNAMENTO: esempio in 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);

ciao, stiamo affrontando lo stesso problema. potresti spiegare più in dettaglio. GRAZIE
user261002

23
Come è questa la risposta corretta? Questo non risponde nemmeno alla domanda. @bomber
GN.

15
Per chiunque legga questo. Se vuoi farlo da un componente figlio. Puoi trovare l'oggetto della cronologia su this.props.history. Quindi, il codice diventathis.props.history.goBack
Sisir

3
Che ne dici di React-Router 4? Non credo che supporti più BrowserHistory.
Akshay Lokur

1
A partire dalla versione 5 di react-router-dom, la cronologia viene creata da BrowserRouter implicitamente ed è disponibile tramite gli oggetti di scena, è possibile accedervi tramite props.history.
Srikanth Kyatham

98

Aggiornamento con React v16 e ReactRouter v4.2.0 (ottobre 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>
    )
  }
}

Aggiornamento con React v15 e ReactRouter v3.0.0 (agosto 2016):

var browserHistory = ReactRouter.browserHistory;

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

Creato un violino con un esempio un po 'più complesso con un iframe incorporato: https://jsfiddle.net/kwg1da3a/

React v14 e ReacRouter v1.0.0 (10 settembre 2015)

Puoi farlo:

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

Devi stare attento ad avere la cronologia necessaria per tornare indietro. Se premi direttamente la pagina e poi premi di nuovo, verrai riportato alla cronologia del browser prima della tua app.

Questa soluzione si prenderà cura di entrambi gli scenari. Tuttavia, non gestirà un iframe che può navigare all'interno della pagina (e aggiungerlo alla cronologia del browser), con il pulsante Indietro. Francamente, penso che sia un bug nel router di reazione. Problema creato qui: https://github.com/rackt/react-router/issues/1874


Sarebbe bello se ci fosse un modo per farlo senza usare il contesto?
Adam D

1
Inoltre, a seconda della configurazione, potrebbe essere utilizzato this.props.history.goBack invece di this.context.router.history.goBack
PhoenixB

54
  1. importare withRouter

    import { withRouter } from 'react-router-dom';
  2. Esporta il tuo componente come:

    export withRouter(nameofcomponent) 
  3. Esempio, al clic del pulsante, chiama goBack:

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

Testato su react-router-domv4.3


2
BTW funziona per me anche senza importare o utilizzare withRouter. Forse stiamo solo usando l'API nativa della cronologia del browser. Ma va bene?
Gianfranco P.

1
È una bella soluzione. L'unico problema quando l'utente accede alla pagina utilizzando l'URL diretto -> interromperà l'app in quanto non ha cronologia.
skryvets

2
Migliore spiegazione qui
Z_z_Z

@MichaelFreidgeim puoi caricare il tuo snippet di codice così lo controllerò e lo verificherò
gaurav makwana

43
this.context.router.goBack()

Nessun mixin di navigazione richiesto!


1
Funziona ancora in React Router v4, ma lo è this.context.router.history.goBack. (+ storia)
Ben Gotow

13
Con react-router-dom: "v4.2.2" e import { withRouter } from 'react-router-dom';funziona conthis.props.history.goBack();
felansu

1
oltre al commento di @ felansu devi anche esportare il tuo componente con Router come spiegato nella risposta stackoverflow.com/a/49130220/3123338
Mister Q

32

Metodo ES6 senza mixin che utilizza la funzione React-Router, stateless.

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

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

3
Ricevo un avviso del browser quando provo la tua soluzione:export 'browserHistory' was not found in 'react-router'
Ralph David Abernathy

2
browserHistory esiste solo in v2 e v3. Se usi la v4 dovresti leggere la guida alla migrazione: github.com/ReactTraining/react-router/blob/…
ptorsson

@Ralp, se ricevi questo messaggio di errore, controlla questo: stackoverflow.com/questions/49787659/…
Miles M.

13

Utilizzo di React Hooks

Importare:

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

Nel componente apolidi:

  let history = useHistory();

All'evento

history.goBack()

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

Grazie per averlo menzionato perché mi piacciono i ganci. Finora ho usato withRouter.
newman

10

Guarda il mio esempio funzionante usando React 16.0 con React-router v4 Live Example . controlla il codice Github

Usa withRouterehistory.goBack()

Questa è l'idea che sto realizzando ...

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 scusate il codice è troppo grande per postare tutto qui


1
Questa dovrebbe essere la risposta accettata a partire da '19. React Router fornisce un componente di ordine superiore (HOC) chiamato "withRouter" in modo da poter avvolgere il componente per avere accesso a oggetti di scena come la cronologia e la posizione.

1
sì, come in WithRouter in HOC nel confezionare la tua parte componente, fornirà la cronologia ei dati sulla posizione. Niente di impegnativo continua a leggere e non si accontenta mai.
Anupam Maurya

Posso chiederti perché passi il segno più alla gofunzione history.go(+1):? history.go(1)dovrebbe essere sufficiente.
gion_13

10

Funziona con la cronologia del browser e dell'hash.

this.props.history.goBack();

8

Questo è un componente BackButton funzionante (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;

Ovviamente puoi fare qualcosa di simile se non c'è storia:

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

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

7

Per React-Router v2.x questo è cambiato. Ecco cosa sto facendo per 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

Torna alla pagina specifica :

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

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

Torna alla pagina precedente :

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

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

2
grazie, questa è un'ottima risposta per il 2020! La risposta accettata è stata così 2015.
beeftosino

5

In react-router v4.x puoi usare history.goBackche è equivalente a 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);

Demo: https://codesandbox.io/s/ywmvp95wpj

Ricorda che utilizzando i historytuoi utenti puoi uscire perché history.goBack()possono caricare una pagina che il visitatore ha visitato prima di aprire la tua applicazione.


Per evitare tale situazione come descritto sopra, ho creato una semplice libreria React-Router-Last-Location che controlla l'ultima posizione dei tuoi utenti.

L'utilizzo è molto semplice. Per prima cosa devi installare react-router-dome react-router-last-locationdanpm .

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

Quindi usa LastLocationProvider come di seguito:

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


Come inseriresti l'oggetto LastLocation nel componente che ne ha bisogno, ovvero mi piacerebbe usarlo a livello di codice, piuttosto che in alcuni output visualizzati come i tuoi esempi: if (lastLocation == 'about')
dmayo

Non sono sicuro di averti capito correttamente, quindi correggimi se sbaglio. Ti piacerebbe usarlo lastLocational di fuori di React o forse dicendo I'd like to use it programmatically, vuoi solo avere la possibilità di importarlo in questo modo import { lastLocation } from '...'?
hinok

5

Quello che ha funzionato per me è stato importare con Router all'inizio del mio file;

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

Quindi usalo per racchiudere la funzione esportata nella parte inferiore del mio file;

export default withRouter(WebSitePageTitleComponent)

Che poi mi ha permesso di accedere alla cronologia del router. Codice di esempio completo di seguito!

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

Sto usando queste versioni

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

2

L'unica soluzione che ha funzionato per me è stata la più semplice. Non sono necessarie ulteriori importazioni.

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

Tks, IamMHussain


Molto bella. Semplice e umile
Dinesh Kanivu

1

Chiama il seguente componente in questo modo:

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

Ed ecco il componente:

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

Sto usando:

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

1

REDUX

Puoi anche usare react-router-reduxche ha goBack()e push().

Ecco un pacchetto di campionamento per questo:

Nel punto di ingresso della tua app, hai bisogno ConnectedRoutere una connessione a volte complicata da collegare è l' historyoggetto. Il middleware Redux ascolta le modifiche alla cronologia:

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

Ti mostrerò un modo per collegare il file history. Nota come la cronologia viene importata nello store ed esportata anche come singleton in modo che possa essere utilizzata nel punto di ingresso dell'app:

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

Il blocco di esempio sopra mostra come caricare gli react-router-reduxhelper middleware che completano il processo di configurazione.

Penso che questa parte successiva sia completamente extra, ma la includerò nel caso in cui qualcuno in futuro ne tragga vantaggio:

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

export default combineReducers({
  routing, form,
})

Lo uso routerReducersempre perché mi permette di forzare il ricaricamento di componenti che normalmente non sono dovuti a shouldComponentUpdate. L'esempio ovvio è quando si dispone di una barra di navigazione che dovrebbe aggiornarsi quando un utente preme un NavLinkpulsante. Se segui questa strada, imparerai che utilizza il metodo di connessione di Redux shouldComponentUpdate. Con routerReducer, puoi usare mapStateToPropsper mappare le modifiche al percorso nella barra di navigazione e questo attiverà l'aggiornamento quando l'oggetto della cronologia cambia.

Come questo:

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

export default connect(mapStateToProps)(Nav)

Perdonami mentre aggiungo alcune parole chiave extra per le persone: se il tuo componente non si aggiorna correttamente, indagare shouldComponentUpdaterimuovendo la funzione di connessione e vedere se risolve il problema. In tal caso, inserire il routerReducere il componente si aggiornerà correttamente quando l'URL cambia.

In conclusione, dopo aver fatto tutto ciò, puoi chiamare goBack()o push()ogni volta che vuoi!

Provalo ora in qualche componente casuale:

  1. Importa in connect()
  2. Non hai nemmeno bisogno di mapStateToPropsomapDispatchToProps
  3. Importa in goBack e invia da react-router-redux
  4. Chiamata this.props.dispatch(goBack())
  5. Chiamata this.props.dispatch(push('/sandwich'))
  6. Prova un'emozione positiva

Se hai bisogno di più campioni, controlla: https://www.npmjs.com/package/react-router-redux


1

Usalo semplicemente in questo modo

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

1

React Router v6

useNavigate Hook è il modo consigliato per tornare indietro ora:

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 campione

Torna indietro / avanti di più voci dello stack della cronologia:
<button onClick={() => navigate(-2)}>go two back</button>
<button onClick={() => navigate(2)}>go two forward</button>
Vai a percorso specifico:
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 sostituisce useHistory per supportare meglio l' imminente modalità React Suspense / Concurrent.


Ho provato a provare ma ho ricevuto l'errore:Attempted import error: 'useNavigate' is not exported from 'react-router-dom'.
Geek

1
@ Geek buona cattura. Con v6.0.0-beta.0, gli sviluppatori hanno reso il historypacchetto una dipendenza peer. Dai un'occhiata al Codesandbox aggiornato, che ora funziona di nuovo.
ford04

0

Questo pezzo di codice farà il trucco per te.

this.context.router.history.goBack()

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.