Navigazione programmatica tramite il router di reazione


1431

Con react-routerposso usare l' Linkelemento per creare collegamenti che sono gestiti in modo nativo dal router di reazione.

Vedo internamente che chiama this.context.transitionTo(...).

Voglio fare una navigazione. Non da un collegamento, ma da una selezione a discesa (come esempio). Come posso farlo nel codice? Che cosa è this.context?

Ho visto il Navigationmixin, ma posso farlo senza mixins?


26
@SergioTapia tieni a mente che questa domanda si trova a cavallo tra una versione principale di Reat-router, una versione principale di React e una versione principale di javascript
George Mauer,

5
Ecco un link al tutorial nei documenti ufficiali del reagente
chitzui

4
Si potrebbe verificare questa risposta stackoverflow.com/questions/44127739/...
Shubham Khatri

4
Sono contento che tu abbia ottenuto una risposta, ma sono triste che debba essere così complicato. La navigazione all'interno di un'app Web dovrebbe essere semplice e ben documentata. VueJS lo rende banale. A ciascun componente viene iniettata automaticamente l'istanza del router. C'è una sezione chiaramente definita per questo nei loro documenti. router.vuejs.org/guide/essentials/navigation.html Mi piace React per molte cose, ma a volte è troppo complicato. </rant>
colefner,

7
@GeorgeMauer Hai ragione. Non è di questo che tratta questa community. Si tratta di rispondere a domande, non di litigare su framework. Grazie per il promemoria.
Colefner,

Risposte:


1436

React Router v5.1.0 con ganci

C'è un nuovo useHistoryhook in React Router> 5.1.0 se si utilizza React> 16.8.0 e componenti funzionali.

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

Con v4 di React Router, esistono tre approcci che è possibile adottare per il routing programmatico all'interno dei componenti.

  1. Utilizzare il withRoutercomponente di ordine superiore.
  2. Usa composizione e rendering a <Route>
  3. Usa il context.

React Router è principalmente un wrapper per la historylibreria. historygestisce l'interazione con il browser window.historyper te con il suo browser e la cronologia hash. Fornisce inoltre una cronologia della memoria che è utile per ambienti che non hanno una cronologia globale. Ciò è particolarmente utile nello sviluppo di app mobili ( react-native) e nei test delle unità con Node.

Un historyesempio ha due metodi per navigare: pushe replace. Se si pensa a historycome una matrice di posizioni visitate, pushsi aggiungerà una nuova posizione alla matrice e replacesi sostituirà la posizione corrente nella matrice con quella nuova. In genere si desidera utilizzare il pushmetodo durante la navigazione.

Nelle versioni precedenti di Reagire router, si doveva creare il proprio historyesempio, ma in v4 la <BrowserRouter>, <HashRouter>e <MemoryRouter>componenti creeranno un browser, hash, e le istanze di memoria per voi. React Router rende disponibili le proprietà e i metodi historydell'istanza associata al router nel contesto, sotto l' routeroggetto.

1. Utilizzare il withRoutercomponente di ordine superiore

Il withRoutercomponente di ordine superiore inietterà l' historyoggetto come prop del componente. Questo ti permette di accedere ai metodi pushe replacesenza dover affrontare il 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. Usa composizione e rendering a <Route>

Il <Route>componente non è solo per le posizioni corrispondenti. È possibile eseguire il rendering di un percorso senza percorso e corrisponderà sempre alla posizione corrente . Il <Route>componente passa gli stessi puntelli di withRouter, così sarai in grado di accedere ai historymetodi attraverso il historypuntello.

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

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

3. Usa il contesto *

Ma probabilmente non dovresti

L'ultima opzione è quella che si dovrebbe usare se si sente di lavoro comodo con del React contesto del modello (React API contesto è stabile della 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 sono le scelte più semplici da implementare, quindi per la maggior parte dei casi d'uso sono le tue migliori scommesse.


24
Ho provato a utilizzare il metodo 1 in questo modo conRouter (({history}) => {console.log ("hhhhhhhh"); history.push ('/ bets')}); Ma non ha mai funzionato con il router 4
Dmitry Malugin

57
CHE COSA!? Posso semplicemente usare withRouterinvece di passare historyattraverso tutti i miei componenti ?? Gahh ho bisogno di passare più tempo a leggere documenti ...
ciaojeffhall,

18
Come si può semplicemente eseguire history.push('/new-location')senza associare quel comportamento a un pulsante o altro elemento DOM?
Neil,

4
errore di lancio comeUnexpected use of 'history' no-restricted-globals
Pardeep Jain,

18
contextnon è più sperimentale dalla reazione 16.
trysis

921

React-Router 5.1.0+ Risposta (usando hook e React> 16.8)

È possibile utilizzare il nuovo useHistoryhook su Componenti funzionali e navigare programmaticamente:

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

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

React-Router 4.0.0+ Risposta

In 4.0 e versioni successive, utilizzare la cronologia come supporto del componente.

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

NOTA: this.props.history non esiste nel caso in cui il componente non sia stato renderizzato <Route>. Si dovrebbe usare <Route path="..." component={YourComponent}/>per avere this.props.history in YourComponent

React-Router 3.0.0+ Risposta

In 3.0 e versioni successive, utilizzare il router come supporto per il componente.

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

React-Router 2.4.0+ Risposta

In 2.4 e versioni successive, utilizzare un componente di ordine superiore per ottenere il router come supporto del 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+ Risposta

Questa versione è retrocompatibile con 1.x quindi non è necessaria una guida all'aggiornamento. Basta passare attraverso gli esempi dovrebbe essere abbastanza buono.

Detto questo, se desideri passare al nuovo modello, c'è un modulo browserHistory all'interno del router a cui puoi accedere

import { browserHistory } from 'react-router'

Ora hai accesso alla cronologia del tuo browser, quindi puoi fare cose come push, sostituire, ecc ... Come:

browserHistory.push('/some/path')

Ulteriori letture: storie e navigazione


React-Router 1.xx Risposta

Non entrerò nei dettagli di aggiornamento. Puoi leggere questo nella Guida all'aggiornamento

Il principale cambiamento sulla domanda qui è il passaggio dal mix di Navigazione alla Cronologia. Ora utilizza l'API della cronologia del browser per modificare il percorso, quindi utilizzeremo pushState()da ora in poi.

Ecco un esempio usando Mixin:

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

Si noti che questo Historyproviene dal progetto rackt / history . Non dallo stesso React-Router.

Se non vuoi usare Mixin per qualche motivo (forse a causa della classe ES6), puoi accedere alla cronologia che ricevi dal router this.props.history. Sarà accessibile solo per i componenti resi dal tuo router. Pertanto, se si desidera utilizzarlo in qualsiasi componente figlio, è necessario passarlo come attributo tramite props.

Puoi leggere ulteriori informazioni sulla nuova versione nella loro documentazione 1.0.x.

Ecco una pagina di aiuto specifica sulla navigazione all'esterno del componente

Si consiglia di prendere un riferimento history = createHistory()e invocarlo replaceState.

React-Router 0.13.x Risposta

Ho riscontrato lo stesso problema e ho trovato la soluzione solo con il mix di navigazione fornito con reagente-router.

Ecco come l'ho fatto

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

Sono stato in grado di chiamare transitionTo()senza la necessità di accedere.context

Oppure potresti provare la fantasia 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 si sta utilizzando Redux, v'è un altro progetto chiamato ReactRouter-Redux che ti dà Redux associazioni per ReactRouter, utilizzando un po 'lo stesso approccio che React-Redux fa

React-Router-Redux ha alcuni metodi disponibili che consentono una semplice navigazione dall'interno dei creatori di azioni. Questi possono essere particolarmente utili per le persone che hanno un'architettura esistente in React Native e desiderano utilizzare gli stessi schemi in React Web con un minimo overhead della caldaia.

Esplora i seguenti metodi:

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

Ecco un esempio di utilizzo, con 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>

3
Sto usando v2.4.0ma l'approccio citato non funziona per me, la mia app non rende a tutti e le uscite della console: Uncaught TypeError: (0 , _reactRouter.withRouter) is not a functionecco il link al mio post SO: stackoverflow.com/questions/37306166/...
nburk

7
Questa dovrebbe essere la risposta accettata, quella accettata è un po 'un casino ed è molto vecchia. @GiantElk Lo faccio funzionare come descritto nella risposta per la versione 2.6.0.
JMac,

2
Questo approccio è ancora il modo raccomandato per la versione 3.0.x? Molte persone sembrano usare la contextstrada.
velop,

6
in 4.0, this.props.history non esiste. Cosa sta succedendo?
Nicolas S.Xu,

4
@ NicolasS.Xu this.props.historynon esiste nel caso in cui il componente non sia stato renderizzato <Route>. Dovresti usare <Route path="..." component={YourComponent}/>per avere this.props.historydentro YourComponent.
vogdb,

508

React-Router v2

Per la versione più recente (v2.0.0-rc5 ), il metodo di navigazione consigliato è premendo direttamente sul singleton della cronologia. Puoi vederlo in azione nel documento Navigazione all'esterno dei componenti .

Estratto pertinente:

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

Se si utilizza l'API reagente-router più recente, è necessario utilizzare historyda this.propsquando all'interno dei componenti, quindi:

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

Offre anche pushStatema è deprecato per gli avvisi registrati.

Se si utilizza react-router-redux, offre una pushfunzione che è possibile inviare in questo modo:

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

Tuttavia, questo può essere utilizzato solo per modificare l'URL, non per navigare effettivamente nella pagina.


15
Non dimenticare che la nuova API non utilizza import { browserHistory } from './react-router'ma crea invece la cronologia utilizzando import createBrowserHistory from 'history/lib/createBrowserHistory'. Successivamente, è possibile accedere historydai componenti di scena:this.props.history('/some/path')
Ricardo Pedroni,

7
var browserHistory = require('react-router').browserHistory; browserHistory.goBack();
Bobby,

7
reazioni-router-redux pushcambia solo l'URL, in realtà non cambia la pagina. Per fare entrambe le cose, l'importazione browserHistoryda react-routere l'uso browserHistory.push('/my-cool-path'). Sfortunatamente, questo non è molto facile da trovare. github.com/reactjs/react-router/blob/master/docs/guides/…
Andrew Samuelsen

4
Sto usando this.props.history.push ('/') ma solo l'URL viene modificato ... Nessun percorso effettivo in corso qui. Cosa mi sto perdendo?
rgcalsaverini,

2
Ho appena caricato la mia react-router
opinione

56

Ecco come farlo react-router v2.0.0con ES6 . react-routersi è allontanato dai mixin.

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
}

5
Credo che l'attuale raccomandazione sia quella di usare il historysingleton come dichiarato da @Bobby. Si potrebbe utilizzare context.router, ma si sta facendo davvero difficile test di unità quei componenti come istanziare solo quel componente non avrà questo nel contesto.
George Mauer,

2
@GeorgeMauer Penso che dipenda da dove è in esecuzione il codice. Secondo i documenti di reazione, si consiglia l'utilizzo di context.router se eseguito sul server. github.com/reactjs/react-router/blob/master/upgrade-guides/…
KumarM

50

React-Router 4.x Risposta:

Da parte mia, mi piace avere un singolo oggetto storico che posso trasportare anche componenti esterni. Quello che mi piace fare è avere un singolo file history.js che importa su richiesta e semplicemente manipolarlo.

Devi solo cambiare BrowserRouter al router e specificare il prop storico. Questo non cambia nulla per te tranne che hai il tuo oggetto storico che puoi manipolare come vuoi.

Devi installare la cronologia , la libreria utilizzata dareact-router .

Esempio di utilizzo, notazione 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 aprile 2018:

Se devi navigare da un componente che è effettivamente reso da a Route componente, puoi anche accedere alla cronologia dagli oggetti di scena, in questo modo:

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

2
Tranne i documenti di React Router ci dicono che non dovresti, nella maggior parte dei casi, usare Routerinvece di BrowserRouter. BrowserRoutercrea e mantiene l' historyoggetto per te. Non dovresti crearne uno tuo solo se ["hai bisogno di una profonda integrazione con strumenti di gestione dello stato come Redux."] Reattraining.com/react-router/web/api/Router
bobbyz

2
È qualcosa che ho imparato nel tempo e nell'esperienza. Mentre di solito è una buona pratica usare il valore predefinito this.props.history, non ho ancora trovato una soluzione che possa aiutarmi a fare una cosa del genere in una classe che non è un componente o qualsiasi altro strumento non costruito come componente React a cui puoi tramandare oggetti di scena. Grazie per il tuo feedback :)
Eric Martin,

44

Per questo, chi non controlla il lato server e per questo sta usando l'hash router v2:

Inserisci la cronologia in un file separato (ad es. App_history.js ES6):

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

export default appHistory;

E usalo ovunque!

Il tuo punto di ingresso per reagire-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"]'));

La tua navigazione all'interno di qualsiasi 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()
  }
})

1
Grazie. Forse mi manca qualcosa. Non è esattamente la stessa delle prime due risposte?
George Mauer,

2
Quando si utilizza la navigazione "hash", in "reazioni-router" v2 è necessario installare la "cronologia" aggiuntiva del modulo (se si desidera evitare strane query di hash) e invece di utilizzare browserHistory è necessario utilizzare useRouterHistory (createHashHistory) ( {queryKey: false}). Questo è il motivo principale per cui l'ho pubblicato. Ho mostrato come navigare con la cronologia hash.
Alexey Volodko,

1
Oh, capisco, hai ragione. Non sto più partecipando a quel progetto, ma penso che il modo preferito sia quello di utilizzare historyper entrambi gli approcci ora
George Mauer,

4
perché questa risposta non è la migliore? perché andare nei guai con Context o HOC o prototipi di eventi, perché non importare semplicemente la cronologia e utilizzarli ovunque ci piaccia?
sto

@storm_buster non c'è nessun compromesso. Abbiamo moduli ES6 e dovremmo usarli! Questa è una tipica dimostrazione dell'uso del tuo strumento (reagisci in questo caso) per tutto, anche per le cose per le quali non vuoi davvero usarle.
Capaj,

40

React Router V4

tl: dr;

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

La risposta semplice e dichiarativa è che è necessario utilizzare <Redirect to={URL} push={boolean} />in combinazione consetState()

push: booleano: se vero, il reindirizzamento spingerà una nuova voce nella cronologia invece di sostituire quella corrente.


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

Esempio completo qui . Leggi di più qui .

PS. L'esempio utilizza gli inizializzatori di proprietà ES7 + per inizializzare lo stato. Guarda anche qui , se sei interessato.


Questa è la migliore risposta che ho trovato. L'uso withRouternon ha funzionato quando era già sulla rotta che viene ricaricata. Nel nostro caso, abbiamo dovuto fare selettivamente setState(causando return <Redirect>) se già sulla rotta o history.push()da altrove.
karmakaze,

Molto, molto intelligente. Eppure molto semplice. Tks. L'ho usato all'interno di ReactRouterTable poiché volevo gestire il clic sull'intera riga. Utilizzato su onRowClick per impostare lo stato. setState ({navigateTo: "/ path /" + row.uuid});
Lovato,

questa è una risposta a prova di proiettile.
Nitin Jadhav,

31

Attenzione: questa risposta copre solo le versioni di ReactRouter precedenti alla 1.0

Dopo aggiornerò questa risposta con i casi d'uso 1.0.0-rc1!

Puoi farlo anche senza mixin.

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

Il gotcha con i contesti è che non è accessibile a meno che non si definisca contextTypesla classe.

Per quanto riguarda il contesto, è un oggetto, come gli oggetti di scena, che vengono tramandati da padre in figlio, ma viene trasmesso implicitamente, senza dover dichiarare ogni volta oggetti di scena. Vedi https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


26

Ho provato almeno 10 modi per farlo prima che qualcosa funzionasse correttamente!

La withRouterrisposta di @Felipe Skinner è stata un po 'travolgente per me, e non ero sicuro di voler creare nuovi nomi di classe "ExportedWithRouter".

Ecco il modo più semplice e pulito per farlo, circa l'attuale React-Router 3.0.0 ed ES6:

React-Router 3.xx con 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);

oppure, se non è la tua classe predefinita, esporta come:

withRouter(Example);
export { Example };

Si noti che in 3.xx, il <Link>componente stesso sta usando router.push, quindi è possibile passarlo in qualsiasi modo si passi il <Link to=tag, come:

   this.props.router.push({pathname: '/some/path', query: {key1: 'val1', key2: 'val2'})'

1
Funziona perfettamente. Ma risponde 200 OKinvece del 30xcodice. Come posso risolvere questo problema?
Muhammad Ateeq Azam,

1
Non sono sicuro. Questo non mi è mai venuto in mente perché non è una richiesta esterna: è solo il tuo browser che utilizza il codice della pagina per modificare ciò che è nella pagina. Puoi sempre effettuare un reindirizzamento javascript manuale se preferisci.
Ben Wheeler,

1
può anche essere usato con @withRouter come decoratore di classe ... va benissimo con mobx
Dan,

21

Per fare la navigazione a livello di codice, è necessario spingere una nuova storia per il props.history nel vostro component, quindi qualcosa come questo può fare il lavoro per voi:

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

Si prega di scrivere la versione di reazione-router
Ash

19

Per i componenti ES6 + React, la seguente soluzione ha funzionato per me.

Ho seguito lo skinner di Felippe, ma ho aggiunto una soluzione end-to-end per aiutare i principianti come me.

Di seguito sono riportate le versioni che ho usato:

"reagire-router": "^ 2.7.0"

"reagire": "^ 15.3.1"

Di seguito è riportato il mio componente di reazione in cui ho utilizzato la navigazione programmatica utilizzando reagente-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;

Di seguito è la configurazione per il mio router:

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

19

Potrebbe non essere l'approccio migliore, ma ... Usando reattivo-router v4, il seguente dattiloscritto potrebbe dare un'idea per alcuni.

Nel componente renderizzato di seguito, ad esempio LoginPage, l' routeroggetto è accessibile e basta chiamare router.transitionTo('/homepage')per navigare.

Il codice di navigazione è stato preso da .

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


1
Perché non usi conRouter e browserHistory?
Erwin Mayer,

1
@Erwin L'API è diversa in v4. Vedi questo github.com/ReactTraining/react-router/issues/3847 .
Mcku,

1
@mcku Dove hai preso il tuo file dts dattiloscritto per reagente-router v4?
jmathew,

1
@jmathew Non ho definizioni di tipo per
reagente

16

In React-Router v4 ed ES6

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

2
Già menzionato in molte altre risposte (anche a lungo nella risposta in alto)
George Mauer,

13

Per utilizzare withRoutercon un componente basato su classe, prova qualcosa di simile di seguito. Non dimenticare di modificare la dichiarazione di esportazione per usare 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);

11

basato sulla risposta precedente
di José Antonio Postigo e Ben Wheeler
la novità? deve essere scritto in dattiloscritto
e l'uso di decoratori
o proprietà / campi statici

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

con qualunque npm installato oggi. "reply-router": "^ 3.0.0" e
"@ types / reply-router": "^ 2.0.41"


11

con React-Router v4 all'orizzonte, ora esiste un nuovo modo di farlo.

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"/>

React-lego è un'app di esempio che mostra come utilizzare / aggiornare il reagente-router e include esempi di test funzionali che navigano nell'app.


5
Questo è ottimo per navigare dalla funzione di rendering, anche se mi chiedo come navigare da qualcosa come un hook del ciclo di vita o redux?
Ruben Martinez Jr.,

11

Nel reagire router v4. Seguo questo doppio modo per instradare programmaticamente.

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

Numero due

Sostituisce la voce corrente nello stack della cronologia

Per ottenere la cronologia degli oggetti di scena, potresti dover avvolgere il tuo componente

withRouter


Grazie!! Migliore risposta
Taha Farooqui,

9

Se stai usando l'hash o la cronologia del browser, puoi farlo

hashHistory.push('/login');
browserHistory.push('/login');

2
hashHistory.push, dà Impossibile leggere la proprietà "push" di undefined. Da dove li importi?
ArchNoob,

import {hashHistory} da "reazioni-router"; puoi importarlo in questo modo in alto.
Zaman Afzal,

Sto usando il tuo esempio di codice dal mio file redux saga, importando proprio come hai detto e lo uso, ma continuo a ottenere quel TypeError.
ArchNoob,

8

Con l'attuale versione di React (15.3), ha this.props.history.push('/location');funzionato per me, ma ha mostrato il seguente avviso:

browser.js: 49 Avviso: [reagire-router] props.historye context.historysono obsoleti. Si prega di utilizzare context.router.

e l'ho risolto usando in context.routerquesto modo:

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;

1
Questo funziona per V4. Bene ... vicino ... deve essere effettivamente this.context.router.history.push ('/ back-location');
velohomme,

7

React-Router V4

se stai usando la versione 4, puoi usare la mia libreria (plug Shameless) dove devi semplicemente inviare un'azione e tutto funziona!

dispatch(navigateTo("/aboutUs"));

Trippler


5

Coloro che stanno affrontando problemi nell'implementazione di questo su reatt-router v4.

Ecco una soluzione funzionante per navigare attraverso l'app di reazione da azioni 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 O file redux

import history from './history' 

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

Tutto grazie a questo commento: commento di ReactTraining


4

Se succede di accoppiare RR4 con redux attraverso reagire-router-redux , utilizzare anche i creatori di azioni di routing react-router-reduxè un'opzione.

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 usi redux thunk / saga per gestire il flusso asincrono, importa i suddetti creatori di azioni in azioni redux e aggancia per reagire i componenti usando mapDispatchToProps potrebbe essere migliore.


1
react-router-reduxè stato deprecato / archiviato per molto tempo
oligofren

4

È inoltre possibile utilizzare il useHistoryhook in un componente senza stato. Esempio dai documenti.

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

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

Nota: i ganci sono stati aggiunti react-router@5.1.0e richiestireact@>=16.8


1
Buona chiamata, potresti notare a quale versione di reagire-router e reagire che fa riferimento? Questa è una nuova modifica che non era sempre disponibile
George Mauer il

3

La risposta giusta era per me al momento della scrittura

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

Ma devi aggiungere PropTypes al tuo componente

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

Non dimenticare di importare PropTypes

import PropTypes from 'prop-types';

Si prega di annotare la versione di reazioni-router, e cosa hai importato da reagire-router
Ash

Nulla da importare e questa è la versione "reagire-router": "^ 4.2.0"
webmaster

3

Forse non è la soluzione migliore ma ottiene il lavoro fatto:

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

Fondamentalmente, una logica legata a un'azione (in questo caso una cancellazione post) finirà per chiamare un trigger per il reindirizzamento. Questo non è l'ideale perché aggiungerai un nodo DOM "trigger" al tuo markup solo per poterlo chiamare comodamente quando necessario. Inoltre, interagirai direttamente con il DOM, che in un componente React potrebbe non essere desiderato.

Tuttavia, questo tipo di reindirizzamento non è richiesto così spesso. Quindi uno o due collegamenti nascosti aggiuntivi nel markup dei componenti non farebbero molto male, soprattutto se dai loro nomi significativi.


Puoi spiegare perché mai dovresti usarlo sulla soluzione accettata?
George Mauer,

È solo una soluzione alternativa al problema discusso. Come già detto, non è l'ideale ma funziona bene per i reindirizzamenti programmatici.
neatsu,

2

Questo ha funzionato per me, non sono necessarie importazioni speciali:

<input 
  type="button" 
  name="back" 
  id="back" 
  class="btn btn-primary" 
  value="Back" 
  onClick={() => { this.props.history.goBack() }} 
/>

Naturalmente questo richiede importazioni speciali: il tuo componente non si è historyaggiunto propssolo a se stesso. Viene da un HoC che dovresti importare per poterlo usare (i componenti inviati direttamente da Routevengono automaticamente avvolti da quel HoC ma poi hai bisogno di un'importazione per Route...)
George Mauer,

2

usa invece il hookrouter, la moderna alternativa al reagente-router

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

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

per rispondere alla domanda OP sul collegamento attraverso la casella di selezione è possibile farlo:

navigate('/about');

FYI. L'autore stesso definisce questa biblioteca "una prova di concetto" e non ha attività da quasi un anno (giugno 2019).
Membro del

@MEMark è perché è già perfetto
StefanBob

Bene, i 38 numeri aperti, insieme al fatto che la versione 2.0 sarà una riscrittura completa secondo l'auther, dice il contrario.
MEMark

1

Per React Router v4 +

Supponendo che non sarà necessario navigare durante il rendering iniziale stesso (per il quale è possibile utilizzare il <Redirect>componente), questo è ciò che stiamo facendo nella nostra app.

Definire un percorso vuoto che restituisce null, ciò consentirà di ottenere l'accesso all'oggetto della cronologia. Devi farlo al livello più alto in cui il tuoRouter è definito.

Ora è possibile fare tutte le cose che si possono fare sulla storia come history.push(), history.replace(), history.go(-1)ecc!

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

1

reagire-router-dom: 5.1.2

  • Questo sito ha 3 pagine, tutte rese dinamicamente nel browser.

  • Sebbene la pagina non si aggiorni mai, nota come React Router mantiene aggiornato l'URL mentre navighi nel sito. Ciò preserva la cronologia del browser, assicurandoti che cose come il pulsante Indietro e i segnalibri funzionino correttamente

  • Uno Switch esamina tutti gli elementi figlio e esegue il rendering del primo il cui percorso corrisponde all'URL corrente. Utilizzare ogni volta che si hanno più percorsi, ma si desidera renderizzare solo uno di questi alla volta

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

Benvenuti in SO! Quando rispondi a una domanda con così tante risposte, prova a mostrare i tuoi vantaggi.
David García Bodego,

Anche questo non risponde alla domanda su come farlo a livello di codice da js imperativo, non con markup.
George Mauer,

1

Quindi, nella mia risposta, ci sono 3 modi diversi per reindirizzare programmaticamente su una route. Alcune delle soluzioni sono già state presentate, ma le seguenti si sono concentrate solo sui componenti funzionali con un'applicazione demo aggiuntiva.

Utilizzando le seguenti versioni:

reagire: 16.13.1

reagente : 16.13.1

reagente-router: 5.2.0

reagire-router-dom: 5.2.0

dattiloscritto: 3.7.2

Configurazione:

Quindi prima di tutto la soluzione sta usando HashRouter, configurata come segue:

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

Dalla documentazione relativa a <HashRouter>:

A <Router>che utilizza la parte di hash dell'URL (ovvero window.location.hash) per mantenere l'interfaccia utente in sincronia con l'URL.

soluzioni:

  1. Usare <Redirect>per spingere usando useState:

Usando in un componente funzionale ( RedirectPushActioncomponente dal mio repository) possiamo usare useStateper gestire il reindirizzamento. La parte complicata è che una volta che è avvenuto il reindirizzamento, dobbiamo redirectripristinare lo stato false. Usando setTimeOutcon 0ritardo stiamo aspettando che React si impegniRedirect sul DOM, quindi riprendiamo il pulsante per usarlo la prossima volta.

Di seguito trovi il mio esempio:

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>
</>

Dalla <Redirect>documentazione:

Il rendering a <Redirect>consente di spostarsi in una nuova posizione. La nuova posizione sovrascriverà la posizione corrente nello stack della cronologia, come fanno i reindirizzamenti lato server (HTTP 3xx).

  1. Usando useHistorygancio:

Nella mia soluzione c'è un componente chiamato UseHistoryActionche rappresenta quanto segue:

let history = useHistory();

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

L' useHistoryhook ci dà accesso all'oggetto della cronologia che ci aiuta a navigare a livello di codice o a cambiare rotta.

  1. Utilizzando withRouter, ottieni il historyda props:

Creato un componente chiamato WithRouterAction, viene visualizzato come di seguito:

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

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

export default withRouter(WithRouterAction);

Lettura dalla withRouterdocumentazione:

Puoi accedere alle historyproprietà dell'oggetto e alla corrispondenza più vicina <Route>tramite il withRoutercomponente di ordine superiore. withRouterpasserà aggiornata match, locatione historypuntelli al componente avvolto ogniqualvolta rende.

demo:

Per una migliore rappresentazione ho creato un repository GitHub con questi esempi, lo trovi di seguito:

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

Spero che questo possa essere d'aiuto!

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