React-router: come invocare manualmente Link?


131

Sono nuovo di ReactJS e di React-Router. Ho un componente che riceve attraverso oggetti di scena un <Link/>oggetto da reag-router . Ogni volta che l'utente fa clic su un pulsante "successivo" all'interno di questo componente, desidero richiamare l' <Link/>oggetto manualmente.

In questo momento, sto usando refs per accedere all'istanza di supporto e facendo clic manualmente sul tag 'a' che <Link/>genera.

Domanda: esiste un modo per invocare manualmente il collegamento (ad es. this.props.next.go)?

Questo è il codice attuale che ho:

//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />

//in Document.js
...
var Document = React.createClass({
   _onClickNext: function() {
      var next = this.refs.next.getDOMNode();
      next.querySelectorAll('a').item(0).click(); //this sounds like hack to me
   },
   render: function() {
      return (
         ...
         <div ref="next">{this.props.next} <img src="rightArrow.png" onClick={this._onClickNext}/></div>
         ...
      );
   }
});
...

Questo è il codice che vorrei avere:

//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />

//in Document.js
...
var Document = React.createClass({
   render: function() {
      return (
         ...
         <div onClick={this.props.next.go}>{this.props.next.label} <img src="rightArrow.png" /> </div>
         ...
      );
   }
});
...

Risposte:


199

React Router v4 - Redirect Component (aggiornato 2017/04/15)

Il modo consigliato v4 è quello di consentire al tuo metodo di rendering di catturare un reindirizzamento. Usa lo stato o gli oggetti di scena per determinare se il componente di reindirizzamento deve essere mostrato (che quindi attiva un reindirizzamento).

import { Redirect } from 'react-router';

// ... your class implementation

handleOnClick = () => {
  // some action...
  // then redirect
  this.setState({redirect: true});
}

render() {
  if (this.state.redirect) {
    return <Redirect push to="/sample" />;
  }

  return <button onClick={this.handleOnClick} type="button">Button</button>;
}

Riferimento: https://reacttraining.com/react-router/web/api/Redirect

React Router v4 - Contesto del router di riferimento

Puoi anche sfruttare Routeril contesto del quale è esposto al componente React.

static contextTypes = {
  router: PropTypes.shape({
    history: PropTypes.shape({
      push: PropTypes.func.isRequired,
      replace: PropTypes.func.isRequired
    }).isRequired,
    staticContext: PropTypes.object
  }).isRequired
};

handleOnClick = () => {
  this.context.router.push('/sample');
}

Ecco come <Redirect />funziona sotto il cofano.

Riferimento: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Redirect.js#L46,L60

React Router v4 - Oggetto storia mutato esternamente

Se hai ancora bisogno di fare qualcosa di simile all'implementazione di v2, puoi creare una copia di BrowserRouterquindi esporre la historycostante esportabile. Di seguito è riportato un esempio di base ma è possibile comporlo per iniettarlo con oggetti di scena personalizzabili, se necessario. Ci sono avvertimenti noti con i cicli di vita, ma dovrebbe sempre eseguire nuovamente il rendering del router, proprio come in v2. Questo può essere utile per i reindirizzamenti dopo una richiesta API da una funzione di azione.

// browser router file...
import createHistory from 'history/createBrowserHistory';
import { Router } from 'react-router';

export const history = createHistory();

export default class BrowserRouter extends Component {
  render() {
    return <Router history={history} children={this.props.children} />
  }
}

// your main file...
import BrowserRouter from './relative/path/to/BrowserRouter';
import { render } from 'react-dom';

render(
  <BrowserRouter>
    <App/>
  </BrowserRouter>
);

// some file... where you don't have React instance references
import { history } from './relative/path/to/BrowserRouter';

history.push('/sample');

Ultime BrowserRouternovità: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/BrowserRouter.js

React Router v2

Invia un nuovo stato browserHistoryall'istanza:

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

Riferimento: https://github.com/reactjs/react-router/blob/master/docs/guides/NavigatingOutsideOfComponents.md


7
hashHistory.push ( '/ campione'); se stai usando hashHistory invece di browserHistory
sanath_p il

1
questo è particolarmente utile nella libreria material-ui poiché l'utilizzo di containerElement = {<Link to = "/" />} non sempre invoca il link
Vishal Disawar,

2
Nota con l'opzione di reindirizzamento è necessario specificare push (cioè <Reindirizzamento push />). Per impostazione predefinita eseguirà una sostituzione che non è affatto la stessa che invoca manualmente un collegamento
aw04

1
@jokab puoi usare <NavLink /> invece di <Link /> github.com/ReactTraining/react-router/blob/master/packages/…
Matt Lo

1
Il reindirizzamento non funziona per me, ma la soluzione aw04 con withRouter è più semplice e funzionante
stackdave

90

React Router 4 include un HOC withRouter che consente di accedere all'oggetto tramite :historythis.props

import React, {Component} from 'react'
import {withRouter} from 'react-router-dom'

class Foo extends Component {
  constructor(props) {
    super(props)

    this.goHome = this.goHome.bind(this)
  }

  goHome() {
    this.props.history.push('/')
  }

  render() {
    <div className="foo">
      <button onClick={this.goHome} />
    </div>
  }
}

export default withRouter(Foo)

9
Questo ha funzionato per me e sembra la soluzione più semplice.
Rubycut,

5
Questa è la soluzione migliore Non capisco perché abbia così pochi voti.
Benoit,

1
Sì, puoi fare clic sul collegamento alcune volte e il browser non funzionerà. dovrai tornare indietro alcune volte sul browser per tornare indietro
Vladyslav Tereshyn

@VladyslavTereshyn puoi aggiungere una logica condizionale: if ((this.props.location.pathname + this.props.location.search)! == navigateToPath) {...}
MattWeiler

15

Nella versione 5.x , è possibile utilizzare useHistoryhook di react-router-dom:

// Sample extracted from https://reacttraining.com/react-router/core/api/Hooks/usehistory
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>
  );
}

Questa è la soluzione migliore Se aggiungi una logica condizionale, puoi evitare voci duplicate nella cronologia quando un utente fa clic più volte sullo stesso pulsante:if ((routerHistory.location.pathname + routerHistory.location.search) !== navigateToPath) { routerHistory.push(navigateToPath); }
MattWeiler

Avevo bisogno di dichiarare historyvariabile, il useHistory().push
richiamo della

questa sembra la più moderna soluzione reattiva.
Youngjae,

8

https://github.com/rackt/react-router/blob/bf89168acb30b6dc9b0244360bcbac5081cf6b38/examples/transitions/app.js#L50

oppure puoi anche provare a eseguire onClick this (soluzione più violenta):

window.location.assign("/sample");

Man mano che le righe di codice cambiano, la tua risposta sarà migliore se copi i dettagli e spieghi la tua risposta qui. Inoltre, assignnon è una proprietà, è una funzione.
WiredPrairie,

(Ma hai ancora un collegamento a una riga specifica di un file). Includi il suggerimento specifico nella tua risposta e non solo un link.
WiredPrairie,

Grazie per la tua risposta @grechut. Tuttavia, voglio assicurarmi che Document non sappia nulla del router. Il comportamento che mi aspetto è: "Se l'utente fa clic sulla freccia destra, invoca la funzione successiva". La funzione successiva potrebbe essere un collegamento o meno.
Alan Souza,

Ho un paio di pagine gestite al di fuori di React (schermate di accesso con FB e reindirizzamenti di Google) quindi ne avevo bisogno nel menu di navigazione per quelle pagine da "browserHistory.push ('/ home');" ha cambiato solo l'URL, non è stato possibile instradare le pagine. Grazie.
Deborah,

7
Ciò ricaricherebbe la pagina @grechut, non un comportamento desiderato per un'applicazione con il router di reazione.
Abhas,

2

Ok, penso di essere riuscito a trovare una soluzione adeguata per questo.

Ora, invece di inviare <Link/>come prop a Document, invio <NextLink/>che è un wrapper personalizzato per il link di reazione-router. In questo modo, sono in grado di avere la freccia destra come parte della struttura di collegamento evitando comunque di avere il codice di routing all'interno dell'oggetto Document.

Il codice aggiornato è simile al seguente:

//in NextLink.js
var React = require('react');
var Right = require('./Right');

var NextLink = React.createClass({
    propTypes: {
        link: React.PropTypes.node.isRequired
    },

    contextTypes: {
        transitionTo: React.PropTypes.func.isRequired
    },

    _onClickRight: function() {
        this.context.transitionTo(this.props.link.props.to);
    },

    render: function() {
        return (
            <div>
                {this.props.link}
                <Right onClick={this._onClickRight} />
            </div>  
        );
    }
});

module.exports = NextLink;

...
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
var nextLink = <NextLink link={sampleLink} />
<Document next={nextLink} />

//in Document.js
...
var Document = React.createClass({
   render: function() {
      return (
         ...
         <div>{this.props.next}</div>
         ...
      );
   }
});
...

PS : se stai utilizzando l'ultima versione di reagente-router potresti dover usare this.context.router.transitionToinvece di this.context.transitionTo. Questo codice funzionerà perfettamente con la versione 0.12.X del reagente-router.


2

Reagisci router 4

Puoi facilmente invocare il metodo push tramite il contesto in v4:

this.context.router.push(this.props.exitPath);

dove contesto è:

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

Utilizzando BrowserRouter, l'oggetto di contesto dei miei componenti non contiene un routeroggetto. Sto facendo qualcosa di sbagliato?
pilau

Stai impostando il contesto nel componente (il secondo blocco sopra)?
Chris

Grazie per aver risposto! alla fine questo ha funzionato per me: router: React.PropTypes.object.isRequired. Non so perché non ha funzionato senza la isRequiredchiave. Inoltre, <Link>sembra essere in grado di ottenere il historycontesto, ma non sono riuscito a replicarlo.
pilau

Interessante: se avessi installato un codice, potrei aiutarti a eseguire il debug se sei ancora bloccato
Chris

Sembra che tu possa usare this.props.history.push()in React Router v4. Ho trovato questo solo ispezionando gli oggetti di scena in cui React Router passa però. Sembra funzionare ma non sono sicuro che sia una buona idea.
sean_j_roberts,

-1

di nuovo questo è JS :) funziona ancora ....

var linkToClick = document.getElementById('something');
linkToClick.click();

<Link id="something" to={/somewhaere}> the link </Link>
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.