React-Router: Wie rufe ich Link manuell auf?

131

Ich bin neu bei ReactJS und bei React-Router. Ich habe eine Komponente, die über Requisiten ein <Link/>Objekt vom React-Router empfängt . Immer wenn der Benutzer auf eine Schaltfläche "Weiter" in dieser Komponente klickt, möchte ich das <Link/>Objekt manuell aufrufen .

Im Moment verwende ich refs, um auf die Sicherungsinstanz zuzugreifen und manuell auf das <Link/>generierte 'a'-Tag zu klicken .

Frage: Gibt es eine Möglichkeit, den Link manuell aufzurufen (z. B. this.props.next.go)?

Dies ist der aktuelle Code, den ich habe:

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

Dies ist der Code, den ich haben möchte:

//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>
         ...
      );
   }
});
...
Alan Souza
quelle

Antworten:

198

React Router v4 - Komponente umleiten (aktualisiert am 15.04.2017)

Die von v4 empfohlene Methode besteht darin, Ihrer Rendermethode zu erlauben, eine Umleitung abzufangen. Verwenden Sie Status oder Requisiten, um zu bestimmen, ob die Umleitungskomponente angezeigt werden muss (was dann eine Umleitung auslöst).

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

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

React Router v4 - Referenz-Router-Kontext

Sie können auch den RouterKontext nutzen, der für die React-Komponente verfügbar ist.

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

So <Redirect />funktioniert es unter der Haube.

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

React Router v4 - Externes Verlaufsobjekt mutieren

Wenn Sie noch etwas Ähnliches wie die Implementierung von v2 tun müssen, können Sie eine Kopie von erstellen und diese BrowserRouterdann historyals exportierbare Konstante verfügbar machen. Unten finden Sie ein grundlegendes Beispiel, aber Sie können es zusammenstellen, um es bei Bedarf mit anpassbaren Requisiten zu versehen. Es gibt einige Einschränkungen bei Lebenszyklen, aber der Router sollte immer neu gerendert werden, genau wie in Version 2. Dies kann für Weiterleitungen nach einer API-Anforderung von einer Aktionsfunktion hilfreich sein.

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

Spätestens BrowserRouterzu erweitern: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/BrowserRouter.js

Reagiere auf Router v2

Verschieben Sie einen neuen Status in die browserHistoryInstanz:

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

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

Matt Lo
quelle
7
hashHistory.push ('/ sample'); Wenn Sie HashHistory anstelle von BrowserHistory verwenden
sanath_p
1
Dies ist besonders nützlich in der Material-UI-Bibliothek, da die Verwendung von containerElement = {<Link to = "/" />} den Link nicht immer aufruft
Vishal Disawar
2
Beachten Sie, dass Sie bei der Umleitungsoption push angeben müssen (dh <Push umleiten />). Standardmäßig wird ersetzt, was keineswegs mit dem manuellen Aufrufen eines Links
identisch ist
1
@jokab Sie können <NavLink /> anstelle von <Link /> github.com/ReactTraining/react-router/blob/master/packages/…
Matt Lo
1
Redirect funktioniert bei mir nicht, aber die aw04-Lösung mit withRouter ist einfacher und funktioniert
stackdave
90

React Router 4 enthält ein withRouter- HOC , mit dem Sie historyüber Folgendes auf das Objekt zugreifen können this.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)
aw04
quelle
9
Das hat bei mir funktioniert und es sieht nach der einfachsten Lösung aus.
Rubycut
5
Dies ist die beste Lösung. Ich verstehe nicht, warum es so wenige Stimmen hat.
Benoit
1
Ja, Sie können einige Male auf den Link klicken und der Browser zurück funktioniert nicht. Sie müssen ein paar Mal auf den Browser klicken, um wirklich zurückzukehren
Vladyslav Tereshyn
@VladyslavTereshyn Sie können eine bedingte Logik hinzufügen: if ((this.props.location.pathname + this.props.location.search)! == navigToPath) {...}
MattWeiler
14

In der Version 5.x können Sie den folgenden useHistoryHook verwenden 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>
  );
}
Paulo Mateus
quelle
Dies ist die beste Lösung. Wenn Sie eine bedingte Logik hinzufügen, können Sie doppelte Einträge im Verlauf vermeiden, wenn ein Benutzer mehrmals auf dieselbe Schaltfläche klickt:if ((routerHistory.location.pathname + routerHistory.location.search) !== navigateToPath) { routerHistory.push(navigateToPath); }
MattWeiler
Ich musste eine historyVariable deklarieren , das Aufrufen von Verzeichnissen useHistory().pushist nach den Hooks-Regeln nicht zulässig
onmyway133
8

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

oder Sie können sogar versuchen, onClick this auszuführen (gewalttätigere Lösung):

window.location.assign("/sample");
grechut
quelle
Wenn sich die Codezeilen ändern, ist Ihre Antwort besser, wenn Sie die Details kopieren und Ihre Antwort hier erläutern. Auch assignist keine Eigenschaft, es ist eine Funktion.
WiredPrairie
(Aber Sie haben immer noch nur einen Link zu einer bestimmten Zeile einer Datei). Bitte fügen Sie Ihrer Antwort den spezifischen Vorschlag hinzu und nicht nur einen Link.
WiredPrairie
Danke für deine Antwort @grechut. Ich möchte jedoch sicherstellen, dass Document überhaupt nichts über Router weiß. Das erwartete Verhalten ist: 'Wenn der Benutzer auf den Rechtspfeil klickt, rufen Sie die nächste Funktion auf'. Die nächste Funktion kann ein Link sein oder nicht.
Alan Souza
Ich habe ein paar Seiten außerhalb von React bearbeitet (Anmeldebildschirme mit FB- und Google-Weiterleitungen), daher brauchte ich diese in der Navigation für diese Seiten seit "browserHistory.push ('/ home');" Nur die URL wurde geändert, die Seiten konnten nicht weitergeleitet werden. Danke dir.
Deborah
7
Dies würde die Seite @grechut neu laden, kein gewünschtes Verhalten für eine Anwendung mit Reaktionsrouter.
Abhas
2

Ok, ich glaube, ich konnte eine richtige Lösung dafür finden.

Anstatt <Link/>als Requisite an Document zu senden, sende ich jetzt <NextLink/>einen benutzerdefinierten Wrapper für den React-Router-Link. Auf diese Weise kann ich den Rechtspfeil als Teil der Link-Struktur verwenden, ohne dass Routing-Code im Document-Objekt enthalten ist.

Der aktualisierte Code sieht folgendermaßen aus:

//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 : Wenn Sie die neueste Version des React-Routers verwenden, müssen Sie möglicherweise this.context.router.transitionTostattdessen verwenden this.context.transitionTo. Dieser Code funktioniert gut für React-Router Version 0.12.X.

Alan Souza
quelle
2

Router reagieren 4

Sie können die Push-Methode einfach über den Kontext in Version 4 aufrufen:

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

wo Kontext ist:

static contextTypes = {
    router: React.PropTypes.object,
};
Chris
quelle
Mit BrowserRouterenthält das Kontextobjekt meiner Komponenten kein routerObjekt. Mache ich etwas falsch
Pilau
Stellen Sie den Kontext in der Komponente ein (der zweite Block oben)?
Chris
Danke, dass du mitgemacht hast! irgendwann hat das bei mir geklappt : router: React.PropTypes.object.isRequired. Ich weiß nicht, warum es ohne isRequiredSchlüssel nicht funktioniert hat . Auch <Link>scheint in der Lage zu sein , die bekommen historyKontext, aber ich konnte es nicht replizieren.
Pilau
Interessant - wenn Sie einen Codepen aufstellen, könnte ich Ihnen beim Debuggen helfen, wenn Sie immer noch nicht
Chris
Es scheint, als könnten Sie this.props.history.push()in React Router v4 verwenden. Ich fand dies nur, indem ich die Requisiten inspizierte, die React Router übergibt. Es scheint zu funktionieren, aber ich bin mir nicht sicher, ob es eine gute Idee ist.
Sean_j_roberts
-1

wieder das ist JS :) das funktioniert immer noch ....

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

<Link id="something" to={/somewhaere}> the link </Link>
taggartJ
quelle