react-router revenir en arrière comment configurer l'historique?

124

Quelqu'un peut-il me dire comment je peux revenir à la page précédente plutôt qu'à un itinéraire spécifique?

Lors de l'utilisation de ce code:

var BackButton = React.createClass({

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

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

Obtenez cette erreur, goBack () a été ignoré car il n'y a pas d'historique du routeur

Voici mes itinéraires:

// 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);
 });
Bombardier
la source
si vous avez trouvé une solution, pourriez-vous s'il vous plaît, partagez-la ici. Merci.
user261002

Réponses:

44

Je pense que vous avez juste besoin d'activer BrowserHistory sur votre routeur par comme ça initialisation de : <Router history={new BrowserHistory}>.

Avant cela, vous devriez exiger BrowserHistoryde'react-router/lib/BrowserHistory'

J'espère que cela aide!

UPDATE: exemple dans 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
la source
salut, nous sommes confrontés au même problème. pourriez-vous s'il vous plaît expliquer plus en détails. MERCI
user261002
23
Comment est-ce la bonne réponse? Cela ne répond même pas à la question. @bomber
GN.
15
Pour quiconque lit ceci. Si vous souhaitez effectuer cette opération à partir d'un composant enfant. Vous pouvez trouver l'objet historique sur this.props.history. Donc, le code devientthis.props.history.goBack
Sisir
3
Que diriez-vous de react-router 4? Je ne pense plus qu'il prend en charge BrowserHistory.
Akshay Lokur
1
Depuis la version 5 de react-router-dom, l'historique est créé implicitement par BrowserRouter et est disponible via les props, vous pouvez y accéder via props.history.
Srikanth Kyatham
98

Mise à jour avec React v16 et ReactRouter v4.2.0 (octobre 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>
    )
  }
}

Mise à jour avec React v15 et ReactRouter v3.0.0 (août 2016):

var browserHistory = ReactRouter.browserHistory;

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

Créé un violon avec un exemple un peu plus complexe avec une iframe intégrée: https://jsfiddle.net/kwg1da3a/

React v14 et ReacRouter v1.0.0 (10 septembre 2015)

Tu peux le faire:

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

Vous devez faire attention à ce que vous ayez l'historique nécessaire pour revenir en arrière. Si vous accédez directement à la page, puis que vous revenez, cela vous ramènera dans l'historique du navigateur avant votre application.

Cette solution prendra en charge les deux scénarios. Cependant, il ne gérera pas une iframe qui peut naviguer dans la page (et ajouter à l'historique du navigateur), avec le bouton retour. Franchement, je pense que c'est un bogue dans le react-router. Problème créé ici: https://github.com/rackt/react-router/issues/1874

mlunoe
la source
Ce serait bien s'il y avait un moyen de le faire sans utiliser le contexte?
Adam D
1
De plus, selon la configuration, il se peut que vous utilisiez this.props.history.goBack au lieu de this.context.router.history.goBack
PhoenixB
54
  1. importer withRouter

    import { withRouter } from 'react-router-dom';
  2. Exportez votre composant sous:

    export withRouter(nameofcomponent) 
  3. Exemple, en cliquant sur un bouton, appelez goBack:

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

Testé sur la react-router-domv4.3

gaurav makwana
la source
2
BTW cela fonctionne pour moi même sans importer ni utiliser withRouter. Peut-être que nous utilisons simplement l'API native de l'historique du navigateur. Mais est-ce que ça va?
Gianfranco P.
1
C'est une belle solution. Le seul problème lorsque l'utilisateur accède à la page en utilisant une URL directe -> cela cassera l'application car elle n'a pas d'historique.
skryvets
2
Meilleure explication ici
Z_z_Z
@MichaelFreidgeim pouvez-vous s'il vous plaît télécharger votre extrait de code afin que je le vérifie et le vérifie
Gaurav Makwana
43
this.context.router.goBack()

Aucun mixin de navigation requis!

ahhhhhhhhhhhhhhhhhhhhhhhhhhhh
la source
1
Cela fonctionne toujours dans React Router v4, mais c'est le cas this.context.router.history.goBack. (+ historique)
Ben Gotow
13
Avec react-router-dom: "v4.2.2" et import { withRouter } from 'react-router-dom';fonctionne avecthis.props.history.goBack();
felansu
1
en plus du commentaire de @ felansu, vous devez également exporter votre composant avec un routeur comme expliqué dans la réponse stackoverflow.com/a/49130220/3123338
Mister Q
32

Méthode ES6 sans mixins utilisant react-router, fonction sans état.

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

export const Test = () => (
  <div className="">
    <button onClick={browserHistory.goBack}>Back</button>
  </div>
)
ptorsson
la source
3
Je reçois un avertissement du navigateur en essayant votre solution:export 'browserHistory' was not found in 'react-router'
Ralph David Abernathy
2
browserHistory n'existe qu'en v2 et v3. Si vous utilisez la v4, vous devriez lire le guide de migration: github.com/ReactTraining/react-router/blob/…
ptorsson
@Ralp, si vous obtenez ce message d'erreur, vérifiez ceci: stackoverflow.com/questions/49787659/…
Miles M.
14

Utilisation des hooks React

Importer:

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

Dans le composant sans état:

  let history = useHistory();

Sur événement

history.goBack()
Eric Roberto
la source
<button onClick = {() => history.goBack ()}> Retour </button>
Hunter
Merci d'avoir mentionné cela parce que j'aime les crochets. Jusqu'à présent, j'utilise withRouter.
newman le
10

Consultez mon exemple de travail utilisant React 16.0 avec React-router v4 Live Example . consultez le code Github

Utiliser withRouterethistory.goBack()

C'est l'idée que je mets en œuvre ...

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 désolé le code est trop gros pour tout poster ici

Morris S
la source
1
Cela devrait être la réponse acceptée à partir de '19. React Router fournit un composant d'ordre supérieur (HOC) appelé "withRouter" afin que vous puissiez encapsuler votre composant pour avoir accès aux accessoires tels que l'historique et l'emplacement.
1
oui comme dans withRouter dans HOC dans votre emballage de votre composant, fournira l'historique et les données de localisation. Rien de difficile n'arrête de lire et ne s'installe jamais.
Anupam Maurya
Puis-je vous demander pourquoi vous passez le signe plus à la gofonction history.go(+1):? history.go(1)Cela devrait suffire.
gion_13
10

Cela fonctionne avec l'historique du navigateur et du hachage.

this.props.history.goBack();
user3322876
la source
8

Ceci est un composant BackButton fonctionnel (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;

Vous pouvez bien sûr faire quelque chose comme ça s'il n'y a pas d'historique:

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

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

Pour react-router v2.x, cela a changé. Voici ce que je fais pour 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
};
as de pique
la source
6

Revenir à une page spécifique :

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

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

Revenir à la page précédente :

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

  const history = useHistory();
  
  const routeChange = () => {
    history.goBack()
  };
Dhahn
la source
2
merci, c'est une excellente réponse 2020! La réponse acceptée était si 2015.
beeftosino
5

Dans react-router v4.x, vous pouvez utiliser history.goBackce qui équivaut à 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);

Démo: https://codesandbox.io/s/ywmvp95wpj

N'oubliez pas qu'en utilisant historyvos utilisateurs peuvent partir car ils history.goBack()peuvent charger une page que le visiteur a visitée avant d'ouvrir votre application.


Pour éviter une telle situation comme décrit ci-dessus, j'ai créé une bibliothèque simple react-router-last-location qui surveille le dernier emplacement de vos utilisateurs.

L'utilisation est très simple. Vous devez d'abord installer react-router-domet à react-router-last-locationpartir de npm.

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

Ensuite, utilisez LastLocationProvidercomme ci-dessous:

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

Démo: https://codesandbox.io/s/727nqm99jj

hinok
la source
Comment pourriez-vous simplement insérer l'objet LastLocation dans le composant qui en a besoin - c'est-à-dire que j'aimerais l'utiliser par programme, plutôt que dans une sortie affichée comme vos exemples: if (lastLocation == 'about')
dmayo
Je ne sais pas si je vous ai bien compris, alors corrigez-moi si je me trompe. Souhaitez-vous utiliser en lastLocationdehors de React ou peut-être en disant I'd like to use it programmatically, voulez-vous simplement pouvoir l'importer comme import { lastLocation } from '...'?
hinok
5

Ce qui a fonctionné pour moi était d'importer avec Routeur en haut de mon fichier;

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

Ensuite, utilisez-le pour envelopper la fonction exportée au bas de mon fichier;

export default withRouter(WebSitePageTitleComponent)

Ce qui m'a ensuite permis d'accéder à l'accessoire historique du routeur. Exemple de code complet ci-dessous!

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)
pantalon-vancy
la source
3
import { withRouter } from 'react-router-dom'

this.props.history.goBack();

J'utilise ces versions

"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
dush88c
la source
2

La seule solution qui fonctionnait pour moi était la plus simple. Aucune importation supplémentaire nécessaire.

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

Tks, IamMHussain

JBarros
la source
Très agréable. Simple and Humble
Dinesh Kanivu
1

Appelez le composant suivant comme ceci:

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

Et voici le composant:

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

J'utilise:

"react": "15.6.1"
"react-router": "4.2.0"
Gal Bracha
la source
1

REDUX

Vous pouvez également utiliser react-router-reduxqui a goBack()etpush() .

Voici un pack d'échantillonneur pour cela:

Dans le point d'entrée de votre application, vous avez besoin ConnectedRouter, et une connexion parfois délicate à connecter est l' historyobjet. Le middleware Redux écoute les changements d'historique:

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

Je vais vous montrer un moyen de brancher le history. Notez comment l'historique est importé dans le magasin et également exporté en tant que singleton afin qu'il puisse être utilisé dans le point d'entrée de l'application:

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

Le bloc d'exemple ci-dessus montre comment charger les react-router-reduxassistants middleware qui terminent le processus de configuration.

Je pense que cette partie suivante est complètement extra, mais je vais l'inclure au cas où quelqu'un dans le futur en trouverait un avantage:

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

export default combineReducers({
  routing, form,
})

J'utilise routerReducertout le temps car cela me permet de forcer le rechargement de composants qui ne sont normalement pas dus à shouldComponentUpdate. L'exemple évident est lorsque vous avez une barre de navigation qui est censée se mettre à jour lorsqu'un utilisateur appuie sur un NavLinkbouton. Si vous suivez cette voie, vous apprendrez que la méthode de connexion de Redux utilise shouldComponentUpdate. Avec routerReducer, vous pouvez utilisermapStateToProps pour mapper les modifications de routage dans la barre de navigation, ce qui déclenchera sa mise à jour lorsque l'objet d'historique changera.

Comme ça:

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

export default connect(mapStateToProps)(Nav)

Pardonnez-moi pendant que j'ajoute des mots-clés supplémentaires pour les personnes: si votre composant ne se met pas à jour correctement, examinez shouldComponentUpdateen supprimant la fonction de connexion et voyez si elle résout le problème. Si tel est le cas, tirez sur routerReduceret le composant se mettra à jour correctement lorsque l'URL change.

En terminant, après avoir fait tout cela, vous pouvez appeler goBack()oupush() tout moment!

Essayez-le maintenant dans un composant aléatoire:

  1. Importer dans connect()
  2. Vous n'avez même pas besoin mapStateToPropsoumapDispatchToProps
  3. Importer dans goBack et pousser depuis react-router-redux
  4. Appel this.props.dispatch(goBack())
  5. Appel this.props.dispatch(push('/sandwich'))
  6. Vivez une émotion positive

Si vous avez besoin de plus d'échantillons, consultez: https://www.npmjs.com/package/react-router-redux

agm1984
la source
1

Utilisez simplement comme ça

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

React Router v6

useNavigate Hook est la méthode recommandée pour revenir maintenant:

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

Échantillon de codesandbox

Revenir en arrière / avancer plusieurs entrées de pile d'historique:
<button onClick={() => navigate(-2)}>go two back</button>
<button onClick={() => navigate(2)}>go two forward</button>
Aller à un itinéraire spécifique:
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 remplace useHistory pour mieux prendre en charge le prochain mode React Suspense / Concurrent.

ford04
la source
J'ai essayé d'essayer cela mais j'ai eu l'erreur:Attempted import error: 'useNavigate' is not exported from 'react-router-dom'.
Geek
1
@Geek bonne prise. Avec v6.0.0-beta.0, les développeurs ont fait du historypackage une dépendance homologue. Jetez un œil à la mise à jour de Codesandbox, qui fonctionne à nouveau maintenant.
ford04
0

Ce morceau de code fera l'affaire pour vous.

this.context.router.history.goBack()
Prajeesh
la source