Navegue programaticamente usando o roteador react

1431

Com react-routereu posso usar o Linkelemento para criar links que são nativamente tratados pelo roteador de reação.

Eu vejo internamente que chama this.context.transitionTo(...).

Eu quero fazer uma navegação. Não de um link, mas de uma seleção suspensa (como exemplo). Como posso fazer isso no código? O que é this.context?

Eu vi o Navigationmixin, mas posso fazer isso sem mixins?

George Mauer
fonte
26
@SergioTapia ter em mente que esta pergunta atravessa um grande lançamento de reagir-router, um grande lançamento de Reagir, E um grande lançamento de javascript
George Mauer
5
Aqui está um link para o tutorial na documentação oficial de reagir v4 router: reacttraining.com/react-router/web/guides/scroll-restoration
chitzui
4
Você pode verificar esta resposta stackoverflow.com/questions/44127739/…
Shubham Khatri
4
Estou feliz que você tenha respondido, mas estou triste que tenha que ser tão complicado. A navegação em um aplicativo Web deve ser fácil e bem documentada. VueJS torna trivial. Cada componente obtém a instância do roteador injetada automaticamente. Há uma seção claramente definida para isso nos documentos. router.vuejs.org/guide/essentials/navigation.html Gosto de reagir para muitas coisas, mas às vezes é muito complicado. </rant>
colefner 24/10
7
@GeorgeMauer Você está certo. Não é disso que trata esta comunidade. É sobre responder perguntas, não brigar sobre estruturas. Obrigado pela lembrança.
Colefner 29/10

Respostas:

1436

React Router v5.1.0 com ganchos

Há um novo useHistorygancho no React Router> 5.1.0 se você estiver usando o React> 16.8.0 e componentes funcionais.

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

function HomeButton() {
  const history = useHistory();

  function handleClick() {
    history.push("/home");
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

React Router v4

Com a v4 do React Router, há três abordagens que você pode adotar para o roteamento programático dentro dos componentes.

  1. Use o withRoutercomponente de ordem superior.
  2. Use a composição e renderize um <Route>
  3. Use o context.

O React Router é principalmente um invólucro em torno da historybiblioteca. historylida com a interação com o navegador window.historypara você com seu histórico de hash e navegador. Ele também fornece um histórico de memória que é útil para ambientes que não possuem um histórico global. Isso é particularmente útil no desenvolvimento de aplicativos móveis ( react-native) e no teste de unidade com o Node.

Uma historyinstância possui dois métodos para navegar: pushe replace. Se você considerar o local historycomo uma matriz de locais visitados, pushadicionará uma nova localização à matriz e replacesubstituirá a localização atual na matriz pela nova. Normalmente, você desejará usar o pushmétodo quando estiver navegando.

Em versões anteriores do Reagir Router, você tinha que criar o seu próprio historyexemplo, mas em v4 o <BrowserRouter>, <HashRouter>e <MemoryRouter>componentes irão criar um navegador, haxixe e instâncias de memória para você. O React Router disponibiliza as propriedades e os métodos da historyinstância associada ao seu roteador por meio do contexto, sob o routerobjeto

1. Use o withRoutercomponente de ordem superior

O withRoutercomponente de ordem superior injeta o historyobjeto como um suporte do componente. Isso permite que você acesse os métodos pushe replacesem precisar lidar com os context.

import { withRouter } from 'react-router-dom'
// this also works with react-router-native

const Button = withRouter(({ history }) => (
  <button
    type='button'
    onClick={() => { history.push('/new-location') }}
  >
    Click Me!
  </button>
))

2. Use composição e renderize um <Route>

O <Route>componente não é apenas para locais correspondentes. Você pode renderizar uma rota sem caminho e ela sempre corresponderá à localização atual . O <Route>componente passa os mesmos adereços que withRouter, portanto, você poderá acessar os historymétodos através do historyadereço.

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

const Button = () => (
  <Route render={({ history}) => (
    <button
      type='button'
      onClick={() => { history.push('/new-location') }}
    >
      Click Me!
    </button>
  )} />
)

3. Use o contexto *

Mas você provavelmente não deveria

A última opção é aquela que você deve usar apenas se sentir-se à vontade para trabalhar com o modelo de contexto do React (a API de contexto do React é estável a partir da v16).

const Button = (props, context) => (
  <button
    type='button'
    onClick={() => {
      // context.history.push === history.push
      context.history.push('/new-location')
    }}
  >
    Click Me!
  </button>
)

// you need to specify the context type so that it
// is available within the component
Button.contextTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  })
}

1 e 2 são as escolhas mais simples de implementar; portanto, na maioria dos casos de uso, são as suas melhores apostas.

Paul S
fonte
24
Tentei usar o método 1 dessa maneira com Router (({history}) => {console.log ("hhhhhhhh"); history.push ('/ bets')}); Mas nunca trabalhou com router 4
Dmitry Malugin
57
O QUE!? Eu só posso usar em withRoutervez de passar historypor todos os meus componentes? GAHH I necessidade de gastar mais docs leitura vez ...
hellojeffhall
18
Como você pode simplesmente executar history.push('/new-location')sem anexar esse comportamento a um Button ou outro elemento DOM?
Neil
4
jogando erro comoUnexpected use of 'history' no-restricted-globals
Pardeep Jain
18
contextnão é mais experimental a partir da reação 16.
trysis 02/09
921

Resposta do React-Router 5.1.0+ (usando ganchos e React> 16.8)

Você pode usar o novo useHistorygancho em Componentes Funcionais e navegar programaticamente:

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

function HomeButton() {
  let history = useHistory();
  // use history.push('/some/path') here
};

React-Router 4.0.0+ Resposta

No 4.0 e acima, use o histórico como suporte do seu componente.

class Example extends React.Component {
   // use `this.props.history.push('/some/path')` here
};

NOTA: this.props.history não existe no caso em que seu componente não foi renderizado <Route>. Você deve usar o <Route path="..." component={YourComponent}/>this.props.history em YourComponent

React-Router 3.0.0+ Resposta

No 3.0 e acima, use o roteador como suporte do seu componente.

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

React-Router 2.4.0+ Resposta

Na 2.4 e acima, use um componente de ordem superior para obter o roteador como suporte do seu componente.

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes
Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

React-Router 2.0.0+ Resposta

Esta versão é compatível com a versão 1.x, portanto não há necessidade de um Guia de atualização. Apenas passar pelos exemplos deve ser bom o suficiente.

Dito isso, se você deseja mudar para o novo padrão, há um módulo browserHistory dentro do roteador que você pode acessar com

import { browserHistory } from 'react-router'

Agora você tem acesso ao histórico do navegador, para poder executar ações como empurrar, substituir, etc ...

browserHistory.push('/some/path')

Leitura adicional: Histórias e navegação


Resposta do React-Router 1.xx

Não entrarei em detalhes de atualização. Você pode ler sobre isso no Guia de atualização

A principal mudança sobre a questão aqui é a mudança do Navigation mixin para o History. Agora, ele está usando a API do histórico do navegador para alterar a rota, e usaremos a pushState()partir de agora.

Aqui está um exemplo usando o Mixin:

var Example = React.createClass({
  mixins: [ History ],
  navigateToHelpPage () {
    this.history.pushState(null, `/help`);
  }
})

Observe que isso Historyvem do projeto rackt / history . Não do próprio React-Router.

Se você não quiser usar o Mixin por algum motivo (talvez por causa da classe ES6), poderá acessar o histórico que obtém do roteador this.props.history. Ele estará acessível apenas para os componentes renderizados pelo seu roteador. Portanto, se você quiser usá-lo em qualquer componente filho, ele precisará ser transmitido como um atributo via props.

Você pode ler mais sobre a nova versão na documentação 1.0.x

Aqui está uma página de ajuda especificamente sobre como navegar fora do seu componente

Ele recomenda pegar uma referência history = createHistory()e solicitar replaceStateisso.

Resposta do roteador React 0.13.x

Eu entrei no mesmo problema e só consegui encontrar a solução com o Navegador mixin que acompanha o reat-router.

Aqui está como eu fiz isso

import React from 'react';
import {Navigation} from 'react-router';

let Authentication = React.createClass({
  mixins: [Navigation],

  handleClick(e) {
    e.preventDefault();

    this.transitionTo('/');
  },

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

Consegui ligar transitionTo()sem a necessidade de acessar.context

Ou você pode experimentar o sofisticado ES6 class

import React from 'react';

export default class Authentication extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();

    this.context.router.transitionTo('/');
  }

  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
}

Authentication.contextTypes = {
  router: React.PropTypes.func.isRequired
};

React-Router-Redux

Nota: se você estiver usando Redux, há um outro projeto chamado ReactRouter-Redux que lhe dá Redux ligações para ReactRouter, usando um pouco a mesma abordagem que Reagir-Redux faz

O React-Router-Redux possui alguns métodos disponíveis que permitem uma navegação simples a partir de criadores de ação interna. Isso pode ser particularmente útil para pessoas que possuem arquitetura existente no React Native e desejam utilizar os mesmos padrões no React Web com o mínimo de sobrecarga.

Explore os seguintes métodos:

  • push(location)
  • replace(location)
  • go(number)
  • goBack()
  • goForward()

Aqui está um exemplo de uso, com Redux-Thunk :

./actioncreators.js

import { goBack } from 'react-router-redux'

export const onBackPress = () => (dispatch) => dispatch(goBack())

./viewcomponent.js

<button
  disabled={submitting}
  className="cancel_button"
  onClick={(e) => {
    e.preventDefault()
    this.props.onBackPress()
  }}
>
  CANCEL
</button>
Felipe Skinner
fonte
3
Estou usando, v2.4.0mas a abordagem mencionada não funciona para mim, meu aplicativo não é processado e o console sai: Uncaught TypeError: (0 , _reactRouter.withRouter) is not a functionaqui está o link para minha postagem do SO: stackoverflow.com/questions/37306166/…
nburk
7
Esta deve ser a resposta aceita, a aceita é um pouco confusa e é muito antiga. @GiantElk Estou trabalhando como descrito na resposta da versão 2.6.0.
JMac
2
Essa abordagem ainda é a maneira recomendada para a versão 3.0.x? Muitas pessoas parecem usar o contextcaminho.
velop
6
na 4.0, this.props.history não existe. O que está acontecendo?
Nicolas S.Xu
4
@ NicolasS.Xu this.props.historynão existe no caso em que seu componente não foi renderizado <Route>. Você deve usar <Route path="..." component={YourComponent}/>para ter this.props.historyem YourComponent.
vogdb 21/01/19
508

React-Router v2

Para a versão mais recente ( v2.0.0-rc5), o método de navegação recomendado é empurrar diretamente para o singleton do histórico. Você pode ver isso em ação no documento Navegando fora dos componentes .

Trecho relevante:

import { browserHistory } from 'react-router';
browserHistory.push('/some/path');

Se você estiver usando a API do roteador de reação mais recente, precisará usar o historyfrom from this.propsdentro dos componentes para:

this.props.history.push('/some/path');

Ele também oferece, pushStatemas é preterido por avisos registrados.

Se estiver usando react-router-redux, ele oferece uma pushfunção que você pode despachar da seguinte forma:

import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

No entanto, isso pode ser usado apenas para alterar o URL, não para realmente navegar para a página.

Bobby
fonte
15
Não esqueça que a API mais recente não usa, import { browserHistory } from './react-router'mas cria um histórico usando import createBrowserHistory from 'history/lib/createBrowserHistory'. Mais tarde, você pode acessar historya partir dos componentes adereços:this.props.history('/some/path')
Ricardo Pedroni
7
var browserHistory = require('react-router').browserHistory; browserHistory.goBack();
Bobby
7
O react-router-redux pushapenas altera o URL, na verdade não altera a página. Para fazer as duas coisas, a importação browserHistoryde react-routere uso browserHistory.push('/my-cool-path'). Infelizmente, isso não é super fácil de encontrar. github.com/reactjs/react-router/blob/master/docs/guides/…
Andrew Samuelsen
4
Estou usando this.props.history.push ('/'), mas apenas o URL é alterado ... Nenhum roteamento real está acontecendo aqui. o que estou perdendo?
Rgcalsaverini
2
I acabou de enviar a minha opinião sobre como navegar através de programação no último react-routerv4
spik3s
56

Veja como você faz isso react-router v2.0.0com o ES6 . react-routerse afastou dos mixins.

import React from 'react';

export default class MyComponent extends React.Component {
  navigateToPage = () => {
    this.context.router.push('/my-route')
  };

  render() {
    return (
      <button onClick={this.navigateToPage}>Go!</button>
    );
  }
}

MyComponent.contextTypes = {
  router: React.PropTypes.object.isRequired
}
Alex Miller
fonte
5
Acredito que a recomendação atual é usar o historysingleton conforme declarado pelo @Bobby. Você poderia usar context.router, mas você está fazendo isso muito difícil de teste de unidade esses componentes como instanciar apenas esse componente não terá isso no contexto.
George Mauer
2
@GeorgeMauer Acho que depende de onde o código está sendo executado. De acordo com os documentos do react, o uso do context.router é recomendado se for executado no servidor. github.com/reactjs/react-router/blob/master/upgrade-guides/…
#
50

Resposta do React-Router 4.x:

No final, gosto de ter um único objeto histórico que possa transportar até componentes externos. O que eu gosto de fazer é ter um único arquivo history.js que importo sob demanda e apenas o manipulo.

Você apenas precisa mudar BrowserRouterpara o roteador e especificar o suporte de histórico. Isso não muda nada para você, exceto que você tem seu próprio objeto de histórico que você pode manipular como quiser.

Você precisa instalar o histórico , a biblioteca usada por react-router.

Exemplo de uso, notação ES6:

history.js

import createBrowserHistory from 'history/createBrowserHistory'
export default createBrowserHistory()

BasicComponent.js

import React, { Component } from 'react';
import history from './history';

class BasicComponent extends Component {

    goToIndex(e){
        e.preventDefault();
        history.push('/');
    }

    render(){
        return <a href="#" onClick={this.goToIndex}>Previous</a>;
    }
}

EDIT 16 de abril de 2018:

Se você precisar navegar de um componente que é realmente renderizado a partir de um Routecomponente, também poderá acessar o histórico a partir de adereços, assim:

BasicComponent.js

import React, { Component } from 'react';

class BasicComponent extends Component {

    navigate(e){
        e.preventDefault();
        this.props.history.push('/url');
    }

    render(){
        return <a href="#" onClick={this.navigate}>Previous</a>;
    }
}
Eric Martin
fonte
2
Exceto que os documentos do React Router nos dizem que, na maioria dos casos, você não precisa usar em Routervez de BrowserRouter. BrowserRoutercria e mantém o historyobjeto para você. Você não deve usar como padrão para a criação de seu próprio país, só se você [ "necessidade profunda integração com ferramentas de gerenciamento de estado como Redux".] Reacttraining.com/react-router/web/api/Router
bobbyz
2
Isso é algo que aprendi ao longo do tempo e da experiência. Embora geralmente seja uma boa prática usar o padrão this.props.history, ainda não encontrei uma solução que possa me ajudar a fazer algo em uma classe que não seja um componente ou qualquer outra ferramenta que não seja construída como um componente React ao qual você pode passar adereços. Obrigado pelo seu feedback :)
Eric Martin
44

Para este, que não controla o lado do servidor e, por isso, está usando o roteador hash v2:

Coloque seu histórico em um arquivo separado (por exemplo, app_history.js ES6):

import { useRouterHistory } from 'react-router'
import { createHashHistory } from 'history'
const appHistory = useRouterHistory(createHashHistory)({ queryKey: false });

export default appHistory;

E use-o em qualquer lugar!

Seu ponto de entrada para o react-router (app.js ES6):

import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Redirect } from 'react-router'
import appHistory from './app_history'
...
const render((
  <Router history={appHistory}>
  ...
  </Router>
), document.querySelector('[data-role="app"]'));

Sua navegação dentro de qualquer componente (ES6):

import appHistory from '../app_history'
...
ajaxLogin('/login', (err, data) => {
  if (err) {
    console.error(err); // login failed
  } else {
    // logged in
    appHistory.replace('/dashboard'); // or .push() if you don't need .replace()
  }
})
Alexey Volodko
fonte
1
Obrigado. Talvez esteja faltando alguma coisa. Não é exatamente o mesmo que as duas principais respostas?
George Mauer 20/03
2
Quando você está usando a navegação "hash", no "react-router" v2, é necessário instalar o módulo "history" adicional (se quiser evitar consultas estranhas de hash) e, em vez de usar o browserHistory, é necessário usar useRouterHistory (createHashHistory) ( {queryKey: false}). Esta é a principal razão pela qual eu postei isso. Eu mostrei como navegar com o histórico de hash.
Alexey Volodko
1
Oh, entendo, você está certo. Não estou nesse projeto mais, mas eu acho que a forma preferida é a utilização historyde qualquer abordagem agora
George Mauer
4
por que essa resposta não é a melhor? por que enfrentar todos os problemas com o contexto, o HOC ou os protótipos de eventos; por que não apenas importar o histórico e usá-lo em qualquer lugar que deseje? apenas tentando entender o trade-off
storm_buster
@storm_buster não há compromisso. Temos módulos ES6 e devemos usá-los! Essa é uma demonstração típica do uso de sua ferramenta (reaja nesse caso) para tudo - mesmo para coisas para as quais você realmente não deseja usá-las.
Capaj
40

React Router V4

tl: dr;

if (navigate) {
  return <Redirect to="/" push={true} />
}

A resposta simples e declarativa é que você precisa usar <Redirect to={URL} push={boolean} />em combinação comsetState()

push: boolean - quando verdadeiro, o redirecionamento enviará uma nova entrada para o histórico em vez de substituir a atual.


import { Redirect } from 'react-router'

class FooBar extends React.Component {
  state = {
    navigate: false
  }

  render() {
    const { navigate } = this.state

    // here is the important part
    if (navigate) {
      return <Redirect to="/" push={true} />
    }
   // ^^^^^^^^^^^^^^^^^^^^^^^

    return (
      <div>
        <button onClick={() => this.setState({ navigate: true })}>
          Home
        </button>
      </div>
    )
  }
}

Exemplo completo aqui . Leia mais aqui .

PS. O exemplo usa inicializadores de propriedades do ES7 + para inicializar o estado. Olhe aqui também, se você estiver interessado.

Lyubomir
fonte
Esta é a melhor resposta que encontrei. O uso withRouternão funcionou quando já estava na rota que está sendo recarregada. No nosso caso, tivemos que fazer seletivamente setState(causar return <Redirect>) se já estiver na rota ou history.push()de outro lugar.
Karmakaze #
Muito, muito esperto. E ainda assim muito simples. Tks. Eu o usei dentro do ReactRouterTable, pois queria manipular o clique em toda a linha. Usado no onRowClick para definir o estado. setState ({navigateTo: "/ path /" + row.uuid});
Lovato
Esta é a resposta à prova de balas.
Nitin Jadhav
31

Aviso: esta resposta cobre apenas as versões ReactRouter anteriores à 1.0

Atualizarei esta resposta com os casos de uso 1.0.0-rc1 depois!

Você pode fazer isso sem mixins também.

let Authentication = React.createClass({
  contextTypes: {
    router: React.PropTypes.func
  },
  handleClick(e) {
    e.preventDefault();
    this.context.router.transitionTo('/');
  },
  render(){
    return (<div onClick={this.handleClick}>Click me!</div>);
  }
});

O problema com os contextos é que ele não está acessível, a menos que você defina o contextTypesna classe.

Quanto ao contexto, é um objeto, como adereços, que é transmitido de pai para filho, mas é transmitido implicitamente, sem precisar redefinir adereços a cada vez. Consulte https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html

Qiming
fonte
26

Eu tentei pelo menos 10 maneiras de fazer isso antes que algo desse certo!

A withRouterresposta de @Felipe Skinner foi um pouco esmagadora para mim, e eu não tinha certeza se queria criar novos nomes de classe "ExportedWithRouter".

Aqui está a maneira mais simples e limpa de fazer isso, por volta do atual React-Router 3.0.0 e ES6:

React-Router 3.xx com ES6:

import { withRouter } from 'react-router';

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
export default withRouter(Example);

ou, se não for sua classe padrão, exporte como:

withRouter(Example);
export { Example };

Observe que no 3.xx, o <Link>próprio componente está sendo usado router.push, para que você possa passar o que quer que você passe na <Link to=tag, como:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'
Ben Wheeler
fonte
1
Funciona totalmente bem. Mas responde em 200 OKvez de 30xcódigo. Como posso corrigir esse problema?
Muhammad Ateeq Azam
1
Não tenho certeza. Isso nunca veio à minha mente porque não é uma solicitação externa - é apenas o seu navegador usando o próprio código da página para alterar o conteúdo da página. Você sempre pode fazer um redirecionamento manual de javascript, se preferir.
Ben Wheeler
1
ele também pode ser usado com @withRouter como um decorador de classe ... vai grande com mobx
Dan
21

Para fazer a navegação programaticamente, você precisa enviar um novo histórico para os props.history no seu component, para que algo assim possa fazer o trabalho por você:

//using ES6
import React from 'react';

class App extends React.Component {

  constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(e) {
    e.preventDefault()
    /* Look at here, you can add it here */
    this.props.history.push('/redirected');
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>
          Redirect!!!
        </button>
      </div>
    )
  }
}

export default App;
Alireza
fonte
Por favor, escreva a versão de reagir-router
Ash
19

Para os componentes do ES6 + React, a seguinte solução funcionou para mim.

Eu segui o skinner Felippe, mas adicionei uma solução completa para ajudar iniciantes como eu.

Abaixo estão as versões que eu usei:

"react-router": "^ 2.7.0"

"reagir": "^ 15.3.1"

Abaixo está meu componente react, onde usei a navegação programática usando o react-router:

import React from 'react';

class loginComp extends React.Component {
   constructor( context) {
    super(context);
    this.state = {
      uname: '',
      pwd: ''
    };
  }

  redirectToMainPage(){
        this.context.router.replace('/home');
  }

  render(){
    return <div>
           // skipping html code 
             <button onClick={this.redirectToMainPage.bind(this)}>Redirect</button>
    </div>;
  }
};

 loginComp.contextTypes = {
    router: React.PropTypes.object.isRequired
 }

 module.exports = loginComp;

Abaixo está a configuração do meu roteador:

 import { Router, Route, IndexRedirect, browserHistory } from 'react-router'

 render(<Router history={browserHistory}>
          <Route path='/' component={ParentComp}>
            <IndexRedirect to = "/login"/>
            <Route path='/login' component={LoginComp}/>
            <Route path='/home' component={HomeComp}/>
            <Route path='/repair' component={RepairJobComp} />
            <Route path='/service' component={ServiceJobComp} />
          </Route>
        </Router>, document.getElementById('root'));
Softwareddy
fonte
19

Pode não ser a melhor abordagem, mas ... Usando o react-router v4, o seguinte TypeScript pode dar uma idéia para alguns.

No componente renderizado abaixo, por exemplo LoginPage, o routerobjeto está acessível e apenas chamarouter.transitionTo('/homepage') para navegar.

O código de navegação foi retirado de .

"react-router": "^4.0.0-2", "react": "^15.3.1",

import Router from 'react-router/BrowserRouter';
import { History } from 'react-history/BrowserHistory';
import createHistory from 'history/createBrowserHistory';
const history = createHistory();

interface MatchWithPropsInterface {
  component: typeof React.Component,
  router: Router,
  history: History,
  exactly?: any,
  pattern: string
}

class MatchWithProps extends React.Component<MatchWithPropsInterface,any> {
  render() {
    return(
      <Match {...this.props} render={(matchProps) => (
             React.createElement(this.props.component, this.props)

        )}
       />
    )
  }
}

ReactDOM.render(
    <Router>
      {({ router }) => (
        <div>
          <MatchWithProps exactly pattern="/" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/login" component={LoginPage} router={router} history={history} />
          <MatchWithProps pattern="/homepage" component={HomePage} router={router} history={history} />
          <Miss component={NotFoundView} />
        </div>
      )}
    </Router>,

   document.getElementById('app')
);

mcku
fonte
1
Por que você não usa withRouter e browserHistory?
Erwin Mayer
1
@ Erwin A API é diferente na v4. Consulte este github.com/ReactTraining/react-router/issues/3847 .
Mcku 3/11
1
@mcku Onde você conseguiu seu arquivo dts typescript para o react-router v4?
jmathew
1
@jmathew Eu não tenho quaisquer definições de tipo para v4 reagem-router
mcku
16

No React-Router v4 e ES6

Você pode usar withRoutere this.props.history.push.

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

class Home extends Component {

    componentDidMount() {
        this.props.history.push('/redirect-to');
    }
}

export default withRouter(Home);
Hossein
fonte
2
Já mencionado em várias outras respostas (incluindo longamente na resposta superior)
George Mauer
13

Para usar withRoutercom um componente baseado em classe, tente algo como isto abaixo. Não se esqueça de alterar a instrução de exportação para usar withRouter:

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

class YourClass extends React.Component {
  yourFunction = () => {
    doSomeAsyncAction(() =>
      this.props.history.push('/other_location')
    )
  }

  render() {
    return (
      <div>
        <Form onSubmit={ this.yourFunction } />
      </div>
    )
  }
}

export default withRouter(YourClass);
Janos
fonte
11

com base na resposta anterior
de José Antonio Postigo e Ben Wheeler
a novidade? deve ser escrito em Texto Dactilografado
e o uso de decoradores
OU propriedade / campo estático

import * as React from "react";
import Component = React.Component;
import { withRouter } from "react-router";

export interface INavigatorProps {
    router?: ReactRouter.History.History;
}

/**
 * Note: goes great with mobx 
 * @inject("something") @withRouter @observer
 */
@withRouter
export class Navigator extends Component<INavigatorProps, {}>{
    navigate: (to: string) => void;
    constructor(props: INavigatorProps) {
        super(props);
        let self = this;
        this.navigate = (to) => self.props.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

/**
 * Non decorated 
 */
export class Navigator2 extends Component<INavigatorProps, {}> {

    static contextTypes = {
        router: React.PropTypes.object.isRequired,
    };

    navigate: (to: string) => void;
    constructor(props: INavigatorProps, context: any) {
        super(props, context);
        let s = this;
        this.navigate = (to) =>
            s.context.router.push(to);
    }
    render() {
        return (
            <ul>
                <li onClick={() => this.navigate("/home")}>
                    Home
                </li>
                <li onClick={() => this.navigate("/about")}>
                    About
                </li>
            </ul>
        )
    }
}

com qualquer npm instalado hoje. "react-router": "^ 3.0.0" e
"@ types / react-router": "^ 2.0.41"

Dan
fonte
11

com o React-Router v4 no horizonte, agora existe uma nova maneira de fazer isso.

import { MemoryRouter, BrowserRouter } from 'react-router';

const navigator = global && global.navigator && global.navigator.userAgent;
const hasWindow = typeof window !== 'undefined';
const isBrowser = typeof navigator !== 'undefined' && navigator.indexOf('Node.js') === -1;
const Router = isBrowser ? BrowserRouter : MemoryRouter;

<Router location="/page-to-go-to"/>

O react-lego é um exemplo de aplicativo que mostra como usar / atualizar o reag-router e inclui exemplos de testes funcionais que navegam no aplicativo.

peter.mouland
fonte
5
Isso é ótimo para navegar a partir da função render, embora eu queira saber como navegar a partir de algo como um gancho de ciclo de vida ou redux?
Ruben Martinez Jr.
11

No roteador de reação v4. Eu sigo estas duas maneiras de rotear programaticamente.

1. this.props.history.push("/something/something")
2. this.props.history.replace("/something/something")

Número dois

Substitui a entrada atual na pilha do histórico

Para obter histórico de adereços, você pode precisar envolver seu componente com

withRouter

saiful619945
fonte
Obrigado!! Melhor resposta
Taha Farooqui
9

Se você estiver usando o hash ou o histórico do navegador, poderá fazer

hashHistory.push('/login');
browserHistory.push('/login');
Zaman Afzal
fonte
2
hashHistory.push, fornece Não é possível ler a propriedade "push" de indefinido. De onde você os importa?
ArchNoob 6/17
import {hashHistory} de "react-router"; você pode importá-lo dessa maneira na parte superior.
Zaman Afzal
Estou usando seu exemplo de código do meu arquivo redux saga, importando exatamente como você disse e o usa, mas continuo recebendo esse TypeError.
ArchNoob 7/09/17
8

Com a versão atual do React (15.3), this.props.history.push('/location');funcionou para mim, mas mostrou o seguinte aviso:

browser.js: 49 Aviso: [react-router] props.historye context.historyestá obsoleto. Por favor use context.router.

e eu resolvi usando context.routerassim:

import React from 'react';

class MyComponent extends React.Component {

    constructor(props) {
        super(props);
        this.backPressed = this.backPressed.bind(this);
    }

    backPressed() {
        this.context.router.push('/back-location');
    }

    ...
}

MyComponent.contextTypes = {
    router: React.PropTypes.object.isRequired
};

export default MyComponent;
José Antonio Postigo
fonte
1
Isso está funcionando para a V4. Bem ... perto ... ele precisa realmente ser this.context.router.history.push ('/ back-location');
Velohomme 9/04
7

React-Router V4

se você estiver usando a versão 4, poderá usar minha biblioteca (plugue Shameless), onde você simplesmente despacha uma ação e tudo funciona!

dispatch(navigateTo("/aboutUs"));

trippler

Garry Taylor
fonte
5

Aqueles que estão enfrentando problemas ao implementá-lo no react-router v4.

Aqui está uma solução funcional para navegar pelo aplicativo de reação a partir de ações de redux.

history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

App.js / Route.jsx

import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
 <Route path="/test" component={Test}/>
</Router>

another_file.js OU arquivo redux

import history from './history' 

history.push('/test') // this should change the url and re-render Test component

Tudo graças a este comentário: ReactTraining issues comment

reflexgravity
fonte
4

Se, por acaso, emparelhar RR4 com redux com react -router-redux , use também as react-router-reduxopções de ação de roteamento .

import { push, replace, ... } from 'react-router-redux'

class WrappedComponent extends React.Component {
  handleRedirect(url, replaceState = true) { 
    replaceState 
      ? this.props.dispatch(replace(url)) 
      : this.props.dispatch(push(url)) 
  }
  render() { ... }
}

export default connect(null)(WrappedComponent)

Se usar redux thunk / saga para gerenciar o fluxo assíncrono, importe os criadores da ação acima em ações redux e conecte-os a reagir componentes usando o mapDispatchToProps, que pode ser melhor.

Xlee
fonte
1
react-router-reduxfoi preterido / arquivados por um longo tempo
oligofren
4

Você também pode usar o useHistorygancho em um componente sem estado. Exemplo dos documentos.

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

  return (
    <button type="button" onClick={() => history.push("/home")}>
      Go home
    </button>
  )
}

Nota: Ganchos foram adicionados [email protected]e requeremreact@>=16.8

Nickofthyme
fonte
1
Boa chamada, você pode observar qual versão do react-router e reagir a que se refere? Esta é uma nova mudança que nem sempre estava disponível
George Mauer 07/10
3

A resposta certa foi para mim no momento em que escrevi

this.context.router.history.push('/');

Mas você precisa adicionar PropTypes ao seu componente

Header.contextTypes = {
  router: PropTypes.object.isRequired
}
export default Header;

Não se esqueça de importar PropTypes

import PropTypes from 'prop-types';
webmaster
fonte
Por favor, anote a versão do react-router e o que você importou do react-router #
277
Nada a importar e esta é a versão "react-router": "^ 4.2.0"
webmaster
3

Talvez não seja a melhor solução, mas faz o trabalho:

import { Link } from 'react-router-dom';

// create functional component Post
export default Post = () => (
    <div className="component post">

        <button className="button delete-post" onClick={() => {
            // ... delete post
            // then redirect, without page reload, by triggering a hidden Link
            document.querySelector('.trigger.go-home').click();
        }}>Delete Post</button>

        <Link to="/" className="trigger go-home hidden"></Link>

    </div>
);

Basicamente, uma lógica vinculada a uma ação (nesse caso, uma exclusão posterior) acabará chamando um gatilho para redirecionamento. Isso não é ideal, pois você adicionará um 'gatilho' do nó DOM à sua marcação para poder chamá-lo convenientemente quando necessário. Além disso, você interagirá diretamente com o DOM, o que em um componente React pode não ser desejado.

Ainda assim, esse tipo de redirecionamento não é necessário com tanta frequência. Portanto, um ou dois links ocultos extras na sua marcação de componente não prejudicariam tanto, especialmente se você lhes der nomes significativos.

neatsu
fonte
Você pode explicar por que você usaria isso na solução aceita?
George Mauer
É apenas uma solução alternativa para o problema discutido. Como já foi dito, não é o ideal, mas funciona bem para redirecionamentos programáticos.
Neatsu
2

Isso funcionou para mim, nenhuma importação especial necessária:

<input 
  type="button" 
  name="back" 
  id="back" 
  class="btn btn-primary" 
  value="Back" 
  onClick={() => { this.props.history.goBack() }} 
/>
JJ_Coder4Hire
fonte
É claro que isso precisa de importações especiais - seu componente não foi historyadicionado propsapenas por si só. Que vem de um hoc, que você precisaria de importação, a fim de uso (componentes enviada diretamente para por Routesão automaticamente envolto por essa hoc, mas então você precisa de uma importação para Route...)
George Mauer
2

use hookrouter, a alternativa moderna ao reag-router

https://www.npmjs.com/package/hookrouter

import { useRoutes, usePath, A} from "hookrouter";

Para responder à pergunta do OP sobre como vincular através da caixa de seleção, você pode fazê-lo:

navigate('/about');
StefanBob
fonte
PARA SUA INFORMAÇÃO. O próprio autor chama essa biblioteca de "prova de conceito" e não tem atividade há quase um ano (junho de 2019).
MEMark
@MEMark é porque já é perfeito
StefanBob
Bem, as 38 questões abertas, juntamente com o fato de que a versão 2.0 será uma reescrita completa de acordo com o autor, diz o contrário.
MEMark
1

Para o React Router v4 +

Supondo que você não precise navegar durante a renderização inicial em si (para a qual você pode usar <Redirect> componente), é isso que estamos fazendo em nosso aplicativo.

Defina uma rota vazia que retorne nulo; isso permitirá que você obtenha acesso ao objeto histórico. Você precisa fazer isso no nível superior, ondeRouter está definido.

Agora você pode fazer tudo o que pode ser feito na históriahistory.push() , como history.replace(), history.go(-1)etc!

import React from 'react';
import { HashRouter, Route } from 'react-router-dom';

let routeHistory = null;

export function navigateTo(path) {
  if(routeHistory !== null) {
    routeHistory.push(path);
  }
}

export default function App(props) {
  return (
    <HashRouter hashType="noslash">
      <Route
        render={({ history }) => {
          routeHistory = history;
          return null;
        }}
      />
      {/* Rest of the App */}
    </HashRouter>
  );
}
Aftab Khan
fonte
1

react-router-dom: 5.1.2

  • Este site possui 3 páginas, todas renderizadas dinamicamente no navegador.

  • Embora a página nem sempre seja atualizada, observe como o React Router mantém o URL atualizado enquanto você navega no site. Isso preserva o histórico do navegador, garantindo que coisas como o botão Voltar e os favoritos funcionem corretamente

  • Um Switch examina todos os elementos filhos e renderiza o primeiro cujo caminho corresponde ao URL atual. Use sempre que houver várias rotas, mas você deseja que apenas uma delas seja renderizada por vez

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";



export default function BasicExample() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/dashboard">Dashboard</Link>
          </li>
        </ul>

        <hr />

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

// You can think of these components as "pages"
// in your app.

function Home() {
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

function About() {
  return (
    <div>
      <h2>About</h2>
    </div>
  );
}

function Dashboard() {
  return (
    <div>
      <h2>Dashboard</h2>
    </div>
  );
}```
GOVINDARAJ
fonte
Bem-vindo ao SO! Quando você responder a uma pergunta com tantas respostas, tente mostrar seus benefícios.
David García Bodego
Isso também não responde à pergunta de como fazê-lo programaticamente a partir de js imperativos, não com marcação.
George Mauer
1

Portanto, na minha resposta, existem três maneiras diferentes de redirecionar programaticamente para uma rota. Algumas das soluções já foram apresentadas, mas as seguintes focaram apenas em componentes funcionais com um aplicativo de demonstração adicional.

Usando as seguintes versões:

reagir: 16.13.1

reação: 16.13.1

react-router: 5.2.0

react-router-dom: 5.2.0

texto datilografado: 3.7.2

Configuração:

Então, antes de tudo, a solução está usando HashRouter, configurada da seguinte maneira:

<HashRouter>
    // ... buttons for redirect

    <Switch>
      <Route exact path="/(|home)" children={Home} />
      <Route exact path="/usehistory" children={UseHistoryResult} />
      <Route exact path="/withrouter" children={WithRouterResult} />
      <Route exact path="/redirectpush" children={RedirectPushResult} />
      <Route children={Home} />
    </Switch>
</HashRouter>

A partir da documentação sobre <HashRouter>:

Um <Router>que usa a parte de hash do URL (ou seja window.location.hash) para manter sua interface do usuário sincronizada com o URL.

Soluções:

  1. Usando <Redirect>para empurrar usando useState:

Usando em um componente funcional ( RedirectPushActioncomponente do meu repositório), podemos usar useStatepara manipular o redirecionamento. A parte complicada é que, uma vez que o redirecionamento aconteceu, precisamos definir o redirectestado novamente false. Usando setTimeOutcom 0atraso, estamos aguardando até que o React confirmeRedirect no DOM e depois retorne o botão para usar na próxima vez.

Por favor, encontre meu exemplo abaixo:

const [redirect, setRedirect] = useState(false);
const handleRedirect = useCallback(() => {
    let render = null;
    if (redirect) {
        render = <Redirect to="/redirectpush" push={true} />

        // in order wait until commiting to the DOM
        // and get back the button for clicking next time
        setTimeout(() => setRedirect(false), 0);
    }
    return render;
}, [redirect]);

return <>
    {handleRedirect()}
    <button onClick={() => setRedirect(true)}>
        Redirect push
    </button>
</>

Da <Redirect>documentação:

A renderização de um <Redirect>navegará para um novo local. O novo local substituirá o local atual na pilha do histórico, como os redirecionamentos do lado do servidor (HTTP 3xx).

  1. Usando useHistorygancho:

Na minha solução, há um componente chamado UseHistoryActionque representa o seguinte:

let history = useHistory();

return <button onClick={() => { history.push('/usehistory') }}>
    useHistory redirect
</button>

O useHistorygancho nos dá acesso ao objeto histórico, o que nos ajuda a navegar ou alterar programaticamente as rotas.

  1. Usando withRouter, obtenha o historyde props:

Criado um componente chamado WithRouterAction, é exibido como abaixo:

const WithRouterAction = (props:any) => {
    const { history } = props;

    return <button onClick={() => { history.push('/withrouter') }}>
        withRouter redirect
    </button>
}

export default withRouter(WithRouterAction);

Leitura da withRouterdocumentação:

Você pode obter acesso às historypropriedades do objeto e à correspondência mais próxima <Route>via withRoutercomponente de ordem superior. withRouterpassará atualizados match, locationehistory props para o componente agrupado sempre que renderizado.

Demo:

Para uma melhor representação, criei um repositório GitHub com estes exemplos, por favor, encontre-o abaixo:

https://github.com/norbitrial/react-router-programmatically-redirect-examples

Eu espero que isso ajude!

norbitrial
fonte