react-router voltar uma página como você configura o histórico?


121

Alguém pode me dizer como posso voltar à página anterior em vez de uma rota específica?

Ao usar este código:

var BackButton = React.createClass({

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

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

Obtenha este erro, goBack () foi ignorado porque não há histórico de roteador

Aqui estão minhas rotas:

// 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 você encontrou uma solução, por favor, compartilhe-a aqui. obrigado.
user261002

Respostas:


43

Eu acho que você só precisa permitir BrowserHistory no seu roteador por intializing-lo assim: <Router history={new BrowserHistory}>.

Antes disso, você deve exigir BrowserHistoryde'react-router/lib/BrowserHistory'

Espero que ajude!

ATUALIZAÇÃO: exemplo em 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);

oi, estamos enfrentando o mesmo problema. você poderia explicar mais em detalhes. OBRIGADO
usuário261002

23
Como esta é a resposta correta? Isso nem mesmo responde à pergunta. @bomber
GN.

14
Para quem está lendo isso. Se você quiser fazer isso a partir de um componente filho. Você pode encontrar o objeto de histórico em this.props.history. Então, o código se tornathis.props.history.goBack
Sisir

3
Que tal react-roteador 4? Eu não acho que ele suporta mais BrowserHistory.
Akshay Lokur

1
A partir da versão 5 do react-router-dom, o histórico é criado pelo BrowserRouter implicitamente e está disponível por meio dos props, você pode acessá-lo por meio do props.history.
Srikanth Kyatham

97

Atualização com React v16 e ReactRouter v4.2.0 (outubro de 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>
    )
  }
}

Atualização com React v15 e ReactRouter v3.0.0 (agosto de 2016):

var browserHistory = ReactRouter.browserHistory;

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

Criou um violino com um exemplo um pouco mais complexo com um iframe incorporado: https://jsfiddle.net/kwg1da3a/

React v14 e ReacRouter v1.0.0 (10 de setembro de 2015)

Você consegue fazer isso:

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

Você precisa ter o cuidado de ter a história necessária para voltar atrás. Se você acessar a página diretamente e depois voltar, isso o levará de volta ao histórico do navegador antes de seu aplicativo.

Esta solução cuidará de ambos os cenários. No entanto, ele não lidará com um iframe que pode navegar dentro da página (e adicionar ao histórico do navegador), com o botão Voltar. Francamente, acho que é um bug no roteador react. Problema criado aqui: https://github.com/rackt/react-router/issues/1874


Seria bom se houvesse uma maneira de fazer isso sem usar contexto?
Adam D

1
Além disso, dependendo da configuração, pode estar usando this.props.history.goBack vez de this.context.router.history.goBack
PhoenixB

54
  1. importar withRouter

    import { withRouter } from 'react-router-dom';
  2. Exporte seu componente como:

    export withRouter(nameofcomponent) 
  3. Exemplo, ao clicar no botão, chame goBack:

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

Testado em react-router-domv4.3


2
BTW funciona para mim mesmo sem importar ou usar withRouter. Talvez estejamos apenas usando a API nativa de histórico do navegador. Mas isso está ok ??
Gianfranco P.

1
Essa é uma boa solução. O único problema quando o usuário acessa a página usando URL direto -> isso vai quebrar o aplicativo, pois não tem histórico.
Skryvets de

2
Melhor explicação aqui
Z_z_Z

@MichaelFreidgeim, você pode enviar seu snippet de código para que eu seja verificado e verificado
gaurav makwana

43
this.context.router.goBack()

Nenhum mixin de navegação necessário!


1
Isso ainda funciona no React Router v4, mas é this.context.router.history.goBack. (+ história)
Ben Gotow

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

1
além do comentário de @felansu, você também precisa exportar seu componente com Roteador, conforme explicado na resposta stackoverflow.com/a/49130220/3123338
Mister Q

32

Método ES6 sem mixins usando função react-router e stateless.

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

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

3
Recebo um aviso do navegador quando tento sua solução:export 'browserHistory' was not found in 'react-router'
Ralph David Abernathy,

2
browserHistory existe apenas na v2 e v3. Se você usa a v4, deve ler o guia de migração: github.com/ReactTraining/react-router/blob/…
ptorsson

@Ralp, se você receber esta mensagem de erro, verifique: stackoverflow.com/questions/49787659/…
Miles M.

13

Usando Ganchos React

Importar:

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

No componente sem estado:

  let history = useHistory();

No Evento

history.goBack()

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

Obrigado por mencionar isso porque eu gosto de ganchos. Tenho usado o withRouter até agora.
newman,

10

Confira meu exemplo de trabalho usando React 16.0 com React-router v4 Live Example . verifique o código Github

Use withRouterehistory.goBack()

Esta é a ideia que estou implementando ...

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 desculpe o código é muito grande para postar tudo aqui


1
Essa deve ser a resposta aceita em '19. O React Router fornece um componente de ordem superior (HOC) chamado "withRouter" para que você possa agrupar seu componente para ter acesso a adereços, como histórico e localização.

1
sim como em withRouter em HOC em seu empacotamento de sua parte do componente, fornecerá o histórico e os dados de localização. Nada desafiador continua lendo e nunca se acomoda.
Anupam Maurya

Posso perguntar por que você passa o sinal de mais para a gofunção history.go(+1):? history.go(1)deve ser suficiente.
gion_13

10

Isso funciona com o histórico do navegador e do Hash.

this.props.history.goBack();

8

Este é um componente BackButton funcional (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;

Claro que você pode fazer algo assim se não houver histórico:

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

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

7

Para o react-router v2.x, isso mudou. Aqui está o que estou fazendo para 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

No react-router v4.x você pode usar o history.goBackque é 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

Lembre-se que ao usar historyseus usuários podem sair porque history.goBack()podem carregar uma página que o visitante já visitou antes de abrir seu aplicativo.


Para evitar tal situação, conforme descrito acima, criei uma biblioteca simples react-router-last-location que observa a última localização dos usuários.

O uso é muito simples. Primeiro você precisa instalar react-router-dome react-router-last-locationpartir npm.

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

Em seguida, use LastLocationProvidercomo abaixo:

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


Como você simplesmente puxaria o objeto LastLocation para o componente que precisa dele - ou seja, eu gostaria de usá-lo programaticamente, em vez de em alguma saída exibida como seus exemplos: if (lastLocation == 'about')
dmayo

Não tenho certeza se entendi corretamente, então corrija-me se estiver errado. Você gostaria de usar lastLocationfora do React ou talvez dizendo I'd like to use it programmatically, deseja apenas ter a capacidade de importá-lo como import { lastLocation } from '...'?
hinok de

5

O que funcionou para mim foi importar com o roteador no topo do meu arquivo;

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

Em seguida, use-o para envolver a função exportada na parte inferior do meu arquivo;

export default withRouter(WebSitePageTitleComponent)

O que me permitiu acessar o histórico do roteador. Código de amostra completo abaixo!

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

Volte para a página específica :

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

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

Volte para a página anterior :

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

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

2
obrigado, esta é uma ótima resposta para 2020! A resposta aceita foi assim 2015.
beeftosino

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

this.props.history.goBack();

Estou usando essas versões

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

2

A única solução que funcionou para mim foi a mais simples. Nenhuma importação adicional necessária.

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

Tks, IamMHussain


Muito agradável. Simples e humilde
Dinesh Kanivu

1

Chame o seguinte componente assim:

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

E aqui está o 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

Estou a usar:

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

1

RESTAURADO

Você também pode usar o react-router-reduxque tem goBack()e push().

Aqui está um pacote de amostra para isso:

No ponto de entrada do seu aplicativo, você precisa ConnectedRouter, e uma conexão às vezes difícil de conectar é o historyobjeto. O middleware Redux escuta as mudanças do histórico:

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

Vou mostrar a você uma maneira de conectar o history. Observe como o histórico é importado para a loja e também exportado como um singleton para que possa ser usado no ponto de entrada do aplicativo:

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

O bloco de exemplo acima mostra como carregar os react-router-reduxajudantes de middleware que completam o processo de configuração.

Acho que a próxima parte é completamente extra, mas vou incluí-la para o caso de alguém no futuro encontrar algum benefício:

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

export default combineReducers({
  routing, form,
})

Eu uso routerReducero tempo todo porque me permite forçar a recarga de componentes que normalmente não fazem shouldComponentUpdate. O exemplo óbvio é quando você tem uma barra de navegação que deve ser atualizada quando um usuário pressiona um NavLinkbotão. Se você seguir esse caminho, aprenderá que o método de conexão do Redux usa shouldComponentUpdate. Com o routerReducer, você pode usar mapStateToPropspara mapear alterações de roteamento na barra de navegação, e isso irá acioná-la para atualizar quando o objeto de histórico for alterado.

Como isso:

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

export default connect(mapStateToProps)(Nav)

Perdoe-me enquanto adiciono algumas palavras-chave extras para as pessoas: se o seu componente não está sendo atualizado corretamente, investigue shouldComponentUpdateremovendo a função de conexão e veja se ela corrige o problema. Nesse caso, extraia o routerReducere o componente será atualizado corretamente quando o URL mudar.

Para encerrar, depois de fazer tudo isso, você pode ligar goBack()ou push()quando quiser!

Experimente agora em algum componente aleatório:

  1. Importar em connect()
  2. Você nem precisa mapStateToPropsoumapDispatchToProps
  3. Importar em goBack e enviar de react-router-redux
  4. Ligar this.props.dispatch(goBack())
  5. Ligar this.props.dispatch(push('/sandwich'))
  6. Experimente emoção positiva

Se precisar de mais amostras, verifique: https://www.npmjs.com/package/react-router-redux


1

Simplesmente use assim

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

0

Este pedaço de código fará o truque para você.

this.context.router.history.goBack()

0

Roteador React v6

useNavigate Ganhar é a maneira recomendada de voltar agora:

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

Amostra de Codesandbox

Voltar / avançar várias entradas da pilha de histórico:
<button onClick={() => navigate(-2)}>go two back</button>
<button onClick={() => navigate(2)}>go two forward</button>
Vá para uma rota específica:
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 substitui useHistory para suportar melhor o próximo modo React Suspense / Concurrent.


Tentei fazer isso, mas recebi o erro:Attempted import error: 'useNavigate' is not exported from 'react-router-dom'.
Geek

1
@Geek boa pegada. Com o v6.0.0-beta.0, os desenvolvedores transformaram o historypacote em uma dependência de mesmo nível. Dê uma olhada no Codesandbox atualizado, que funciona novamente agora.
ford04

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.