Programmgesteuert mit React Router V4 navigieren

335

Ich habe gerade react-routervon v3 auf v4 ersetzt.
Ich bin mir jedoch nicht sicher, wie ich programmgesteuert in der Elementfunktion von a navigieren soll Component. dh in der handleClick()Funktion möchte ich /path/some/wherenach der Verarbeitung einiger Daten navigieren . Früher habe ich das gemacht durch:

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

Aber ich kann solche Schnittstellen in v4 nicht finden.
Wie kann ich mit v4 navigieren?

Colin Witkamp
quelle
3
Sie können auf das Verlaufsobjekt in Version 4 über Requisiten zugreifen: this.props.history.push ('/')
colemerrick
6
Was ist, wenn Sie von einem anderen Ort als einem darauf zugreifen möchten Component? Zum Beispiel innerhalb der Redux-Aktionen.
Maximus S
73
manchmal frage ich mich, warum es so kompliziert ist, einfach von einem Link zum anderen zu wechseln =))
Thai Tran
12
Man würde denken, dass die Umleitung heutzutage nicht mehr so ​​kompliziert wäre.
JohnAllen
Ich fand diesen Beitrag hilfreich: medium.com/@anneeb/redirecting-in-react-4de5e517354a
BioData41

Antworten:

413

Wenn Sie auf Browserumgebungen abzielen, müssen Sie react-router-domstattdessen package verwenden react-router. Sie verfolgen den gleichen Ansatz wie React, um den Kern ( react) und den plattformspezifischen Code ( react-dom, react-native) zu trennen , mit dem subtilen Unterschied, dass Sie nicht zwei separate Pakete installieren müssen, sodass die Umgebungspakete alles enthalten du brauchst. Sie können es Ihrem Projekt hinzufügen als:

yarn add react-router-dom

oder

npm i react-router-dom

Das erste, was Sie tun müssen, ist, eine <BrowserRouter>übergeordnete Komponente in Ihrer Anwendung bereitzustellen . <BrowserRouter>Verwendet die HTML5- historyAPI und verwaltet sie für Sie, sodass Sie sich nicht darum kümmern müssen, sie selbst zu instanziieren und <BrowserRouter>als Requisite an die Komponente weiterzugeben (wie in früheren Versionen erforderlich).

In V4 müssen Sie zum programmgesteuerten Navigieren auf das historyüber React verfügbare Objekt zugreifen , contextsofern Sie eine <BrowserRouter> Anbieterkomponente als oberste übergeordnete Komponente in Ihrer Anwendung haben. Die Bibliothek macht das routerObjekt, das selbst historyeine Eigenschaft enthält, durch den Kontext verfügbar. Die historySchnittstelle bietet mehrere Navigationsmethoden, wie zum Beispiel push, replaceund goBack, unter anderem. Sie können die ganze Liste von Eigenschaften und Methoden überprüfen hier .

Wichtiger Hinweis für Redux / Mobx-Benutzer

Wenn Sie Redux oder Mobx als Statusverwaltungsbibliothek in Ihrer Anwendung verwenden, sind möglicherweise Probleme mit Komponenten aufgetreten, die standortbezogen sein sollten, aber nach dem Auslösen einer URL-Aktualisierung nicht erneut gerendert werden

Das passiert , weil react-routerPässe locationzu den Komponenten des Kontextmodells.

Sowohl Connect als auch Observer erstellen Komponenten, deren shouldComponentUpdate-Methoden einen flachen Vergleich ihrer aktuellen Requisiten und ihrer nächsten Requisiten durchführen. Diese Komponenten werden nur neu gerendert, wenn mindestens eine Requisite geändert wurde. Dies bedeutet, dass sie eine Requisite erhalten müssen, die sich ändert, wenn sich der Standort ändert, um sicherzustellen, dass sie aktualisiert werden, wenn sich der Standort ändert.

Die 2 Lösungsansätze sind:

  • Wickeln Sie Ihre angeschlossene Komponente in einen weglosen <Route />. Das aktuelle locationObjekt ist eine der Requisiten, die a <Route>an die Komponente übergibt, die es rendert
  • Wickeln Sie Ihre verbundene Komponente mit der Komponente withRouterhöherer Ordnung ein, die tatsächlich den gleichen Effekt hat und locationwie eine Requisite injiziert

Abgesehen davon gibt es vier Möglichkeiten, programmgesteuert nach Empfehlungen zu navigieren:

1.- Verwenden einer <Route>Komponente

Es fördert einen deklarativen Stil. Vor Version 4 wurden <Route />Komponenten an die Spitze Ihrer Komponentenhierarchie gesetzt, wobei Sie zuvor über Ihre Routenstruktur nachdenken mussten. Jetzt können Sie jedoch <Route>Komponenten an einer beliebigen Stelle in Ihrem Baum haben, sodass Sie je nach URL eine genauere Steuerung für das bedingte Rendern haben. Routeeinspritzt match, locationund historyals Requisiten in Ihrer Komponente. Die Navigationsmethoden (wie push, replace, goBack...) werden als Eigenschaften der zur Verfügung stehenden historyObjekts.

Es gibt 3 Möglichkeiten , etwas mit einem machen Route, indem man entweder component, renderoder childrenRequisiten, aber nicht verwenden mehr als eine in den gleichen Route. Die Auswahl hängt vom Anwendungsfall ab, aber im Grunde werden die ersten beiden Optionen Ihre Komponente nur rendern, wenn sie pathmit dem URL-Speicherort übereinstimmt, während mit childrender Komponente gerendert wird, ob der Pfad mit dem Speicherort übereinstimmt oder nicht (nützlich zum Anpassen der Benutzeroberfläche basierend auf der URL passend).

Wenn Sie Ihre Komponente Rendering Ausgabe anpassen möchten , müssen Sie Ihre Komponente in einer Funktion wickeln und verwenden Sie die renderOption, um alle anderen Requisiten , um Ihre Komponente zu übergeben Sie es wünschen, abgesehen von match, locationund history. Ein Beispiel zur Veranschaulichung:

import { BrowserRouter as Router } from 'react-router-dom'

const ButtonToNavigate = ({ title, history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    {title}
  </button>
);

const SomeComponent = () => (
  <Route path="/" render={(props) => <ButtonToNavigate {...props} title="Navigate elsewhere" />} />
)    

const App = () => (
  <Router>
    <SomeComponent /> // Notice how in v4 we can have any other component interleaved
    <AnotherComponent />
  </Router>
);

2.- Verwenden von withRouterHoC

Diese Komponente höherer Ordnung injiziert die gleichen Requisiten wie Route. Es beinhaltet jedoch die Einschränkung, dass Sie nur 1 HoC pro Datei haben können.

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

const ButtonToNavigate = ({ history }) => (
  <button
    type="button"
    onClick={() => history.push('/my-new-location')}
  >
    Navigate
  </button>
);


ButtonToNavigate.propTypes = {
  history: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired,
  }),
};

export default withRouter(ButtonToNavigate);

3.- Verwenden einer RedirectKomponente

Wenn Sie a <Redirect>rendern, navigieren Sie zu einem neuen Ort. Aber bedenken Sie, dass standardmäßig die aktuelle Position durch die neue ersetzt wird, wie serverseitige Umleitungen (HTTP 3xx). Der neue Speicherort wird von toprop bereitgestellt. Dies kann eine Zeichenfolge (URL, zu der umgeleitet werden soll) oder ein locationObjekt sein. Wenn Sie stattdessen einen neuen Eintrag in den Verlauf verschieben möchten , übergeben Sie auch eine pushRequisite und setzen Sie sie auftrue

<Redirect to="/your-new-location" push />

4.- Manueller Zugriff routerüber den Kontext

Ein bisschen entmutigt, da der Kontext immer noch eine experimentelle API ist und in zukünftigen Versionen von React wahrscheinlich nicht mehr funktioniert

const ButtonToNavigate = (props, context) => (
  <button
    type="button"
    onClick={() => context.router.history.push('/my-new-location')}
  >
    Navigate to a new location
  </button>
);

ButtonToNavigate.contextTypes = {
  router: React.PropTypes.shape({
    history: React.PropTypes.object.isRequired,
  }),
};

Es ist unnötig zu erwähnen, dass es auch andere Router-Komponenten gibt, die für Nicht-Browser-Ökosysteme gedacht sind, z. B. <NativeRouter>die einen Navigationsstapel im Speicher replizieren und auf die React Native-Plattform abzielen, die über das react-router-nativePaket verfügbar ist .

Für weitere Informationen zögern Sie nicht, die offiziellen Dokumente zu lesen . Es gibt auch ein Video von einem der Co-Autoren der Bibliothek, das eine ziemlich coole Einführung in React-Router v4 bietet und einige der wichtigsten Änderungen hervorhebt.

rgommezz
quelle
2
Ich benutze V4 und das oben genannte funktioniert gut. Ich habe ein bisschen Zeit damit verbracht, mich mit dem V4-Router zu beschäftigen, da es einige seltsame Möglichkeiten zu geben scheint, aber die oben genannten funktionieren definitiv. Ich nehme an, Sie importieren withRoutervonreact-router-dom
Sam Parmenter
3
Ich importiere withRouteraus react-router-dom. Die history.push ändert zwar die URL, scheint aber nicht zu laden, <Route>bis ich die Seite
zwangsweise aktualisiere
1
@rauliyohmc Ich habe mich geirrt. Das Problem ist, dass ich <Router> in einer React-Komponente habe, mit der dekoriert ist @observer, was dieses Problem auslöst . Die Problemumgehung ist für @withRouterjede solche React-Komponente erforderlich.
BreakDS
3
Für diejenigen, die auf diese großartige Antwort stoßen, withRouterist es einfach ein HOC, das eine Routeunter der Haube verwendet. Das bedeutet, dass nur 3 Requisiten, Verlauf, Übereinstimmung und Ort verwendet werden . Im obigen Beispiel scheint es sich pushum eine Requisite zu handeln, withRouterdie hinzugefügt werden würde ButtonToNavigate, aber das ist nicht der Fall. props.history.pushmüsste stattdessen verwendet werden. Hoffe das hilft anderen, die etwas verwirrt waren.
Vinnymac
39
Beeindruckend. browserHistory.push('/path/some/where')scheint einfach zu viel einfacher. Die Autoren versuchen, die imperative Programmierung zu unterbinden, aber manchmal funktioniert es einfach besser!
Lux
149

Der einfachste Weg, dies zu erreichen:

this.props.history.push("/new/url")

Hinweis:

  • Möglicherweise möchten Sie die history propübergeordnete Komponente an die Komponente übergeben, für die Sie die Aktion aufrufen möchten, wenn sie nicht verfügbar ist.
Jikku Jose
quelle
10
Ich benutze 4.0 Router, aber es gibt keinen Verlaufsschlüssel für Requisiten. Wie kann ich es reparieren?
Nicolas S.Xu
41
Wenn Sie nicht this.props.historyin Ihrer Komponente verfügbar sind, können Sie import {withRouter} from 'react-router-dom'und dann export default withRouter(MyComponent)(oder const MyComponent = withRouter(...)) und es wird das historyElement in die Requisiten Ihrer Komponente einfügen .
Malvineous
@ Malvineous das ist interessant, wusste nichts davon! Werde es versuchen!
Jikku Jose
2
Mir muss etwas Grundlegendes fehlen, denn das funktioniert einfach großartig für mich, daher habe ich keine Ahnung, warum alle Antworten so lange Erklärungen erfordern.
Joshua Pinter
wie man verhindert, dass Komponenten erneut bereitgestellt werden history.pushund einfach ein Update auslöst, wie wenn wir auf klicken<Link>
Rahul Yadav
55

Ich hatte ein ähnliches Problem bei der Migration auf React-Router v4, daher werde ich versuchen, meine Lösung unten zu erläutern.

Bitte betrachten Sie diese Antwort nicht als den richtigen Weg, um das Problem zu lösen. Ich kann mir vorstellen, dass eine gute Chance besteht, dass etwas Besseres entsteht, wenn React Router v4 reifer wird und die Beta verlässt (es kann sogar schon existieren und ich habe es einfach nicht entdeckt). .

Für den Kontext hatte ich dieses Problem, weil ich gelegentlich benutze Redux-Saga das Verlaufsobjekt programmgesteuert ändere (z. B. wenn sich ein Benutzer erfolgreich authentifiziert).

Sehen Sie sich in den React Router-Dokumenten die <Router> Komponente an und sehen Sie, dass Sie Ihr eigenes Verlaufsobjekt über eine Requisite übergeben können. Dies ist die Essenz der Lösung - wir die Geschichte Objekt liefern , um React-Routervon einem globalen Modul.

Schritte:

  1. Installieren Sie das Verlaufs-npm-Modul - yarn add history oder npm install history --save
  2. Erstelle eine Datei, die history.jsin deinem App.jsLevel-Ordner aufgerufen wird (dies war meine Präferenz).

    // src/history.js
    
    import createHistory from 'history/createBrowserHistory';
    export default createHistory();`
  3. Fügen Sie dieses Verlaufsobjekt wie folgt zu Ihrer Router-Komponente hinzu

    // src/App.js
    
    import history from '../your/path/to/history.js;'
    <Router history={history}>
    // Route tags here
    </Router>
  4. Passen Sie die URL wie zuvor an, indem Sie Ihr globales Verlaufsobjekt importieren :

    import history from '../your/path/to/history.js;'
    history.push('new/path/here/');

Alles sollte jetzt synchron bleiben, und Sie haben auch Zugriff auf eine Möglichkeit, das Verlaufsobjekt programmgesteuert und nicht über eine Komponente / einen Container festzulegen.

Alex Mann
quelle
5
Diese Änderung hat bei mir funktioniert, aber nur, weil ich außerhalb einer Komponente navigiere. Wenn ich in einer Komponente wie dem OP navigieren würde, würde ich den von @rauliyohmc vorgeschlagenen Ansatz verwenden, indem ich die von der RouteKomponente überlieferten Requisiten verwende .
Dan Ellis
2
Dies ist der empfohlene Ansatz ab 08/17
Spets
2
@Spets In meinem Fall wird der Link nach dem Push ordnungsgemäß aktualisiert, wenn ich diese Art von Ansatz verwende. Die Komponenten werden jedoch nicht ordnungsgemäß gerendert (z. B. wird die Komponente nach dem Aktualisieren des Links nur aktualisiert, wenn Sie die Seitenaktualisierung erzwingen). Wo haben Sie festgestellt, dass dies ein empfohlener Ansatz ist? Irgendwelche Links / Quellen?
cool
2
@ScottCoates Ich habe anhand des obigen Beispiels aussortiert, indem ich zwar den Verlauf als Parameter angegeben habe, aber nachdem ich die Knotenmodule selbst debuggt habe. Im gesamten Web wird häufig ein Fehler beim Importieren von "BrowserHistory as Router" gemacht, wenn stattdessen in der neuesten Version des React-Router-Dom ein anderes Objekt namens "Router" vorhanden ist. Die Verwendung in Kombination mit dem im obigen Beispiel erstellten Verlauf funktioniert einwandfrei.
cool
2
Die URL wird aktualisiert, aber die Seite wird nicht basierend auf dem neuen Stamm gerendert. Irgendeine Lösungsmöglichkeit? Warum ist die Triggerroute so schwierig? Menschen, die reagieren, sind verrückt?
Nicolas S.Xu
43

TL; DR:

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

Die einfache und deklarative Antwort ist, dass Sie <Redirect to={URL} push={boolean} />in Kombination mit verwenden müssensetState()

push: boolean - Wenn true, wird durch Umleiten ein neuer Eintrag in den Verlauf verschoben, anstatt den aktuellen zu ersetzen.


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

Vollständiges Beispiel hier . Lesen Sie hier mehr .

PS. In diesem Beispiel werden ES7 + -Eigenschaftsinitialisierer verwendet, um den Status zu initialisieren. Schauen Sie auch hier , wenn Sie interessiert sind.

Lyubomir
quelle
5
Dies sollte als Antwort akzeptiert werden. Einfachste elegante Lösung! +1 für @lustoykov
Ali Abbas Jaffri
1
Ich habe auch die Navigation in componentDidUpdate auf false zurückgesetzt, da sich meine Schaltfläche in einer Kopfzeile befindet und ansonsten nur einmal navigieren würde.
Peterorum
Dies funktioniert nur, wenn Sie über die Umleitung beim Laden der Seite Bescheid wissen. Wenn Sie auf die Rückkehr eines asynchronen Anrufs warten (z. B. Authentifizierung bei Google oder Ähnlichem), müssen Sie eine der history.push()Methoden verwenden.
Brittohalloran
Nicht wirklich, Sie können dennoch den deklarativen Charakter der Reaktion in Kombination mit der <Redirect /> -Komponente nutzen. Wenn die Seite nicht geladen wird, können Sie auf einen anderen <Redirect />
Lyubomir
@brittohalloran Die Idee dieser Methode unter Verwendung des richtigen Reaktionsrouters besteht darin, sicherzustellen, dass Sie setState verwenden, um ein erneutes Rendern zu erzwingen.
Jemand Besonderes
15

Verwenden Sie useHistoryhook, wenn Sie Funktionskomponenten verwenden

Sie können useHistoryhook verwenden, um die historyInstanz abzurufen.

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

const MyComponent = () => {
  var history = useHistory();

  return (
    <button onClick={() => history.push("/about")}>
      Click me
    </button>
  );
}

Der useHistoryHook gibt Ihnen Zugriff auf die Verlaufsinstanz, mit der Sie navigieren können.

Verwenden Sie die historyEigenschaft innerhalb der Seitenkomponenten

React Router fügt einige Eigenschaften ein, einschließlich historySeitenkomponenten.

class HomePage extends React.Component {
  render() {
    const { history } = this.props;

    return (
      <div>
        <button onClick={() => history.push("/projects")}>
          Projects
        </button>
      </div>
    );
  }
}

Wickeln Sie untergeordnete Komponenten ein withRouter, um Routereigenschaften einzufügen

withRouterDer Wrapper fügt den Komponenten Routereigenschaften hinzu. Mit diesem Wrapper können Sie beispielsweise den Router in die Abmeldeschaltflächenkomponente einfügen, die sich im Benutzermenü befindet.

import { withRouter } from "react-router";

const LogoutButton = withRouter(({ history }) => {
  return (
    <button onClick={() => history.push("/login")}>
      Logout
    </button>
  );
});

export default LogoutButton;
TheMisir
quelle
11

Sie können auch einfach Requisiten verwenden, um auf das Verlaufsobjekt zuzugreifen: this.props.history.push('new_url')

user1445685
quelle
5
Nützlich nur, wenn die Komponente direkt vom Router abstammt. Damit Sie die Verlaufs-Requisite nicht an jede einzelne Komponente weitergeben, in der Sie diese Funktionalität benötigen.
mwieczorek
3
Wenn Sie nicht this.props.historyin Ihrer Komponente verfügbar sind, können Sie import {withRouter} from 'react-router-dom'und dann export default withRouter(MyComponent)(oder const MyComponent = withRouter(...)) und es wird das historyElement in die Requisiten Ihrer Komponente einfügen .
Malvineous
9

Schritt 1: Es gibt nur eine Sache, die oben importiert werden muss:

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

Schritt 2: Übergeben Sie auf Ihrer Route den Verlauf:

<Route
  exact
  path='/posts/add'
  render={({history}) => (
    <PostAdd history={history} />
  )}
/>

Schritt 3: Der Verlauf wird als Teil der Requisiten in der nächsten Komponente akzeptiert, sodass Sie einfach:

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

Das war einfach und sehr mächtig.

cdi-meo
quelle
7

Das funktioniert:

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

const SomeComponent = withRouter(({ history }) => (
    <div onClick={() => history.push('/path/some/where')}>
        some clickable element
    </div>); 
);

export default SomeComponent;
Kaya Toast
quelle
5

Meine Antwort ähnelt der von Alex . Ich bin mir nicht sicher, warum React-Router dies so unnötig kompliziert gemacht hat. Warum sollte ich meine Komponente mit einem HoC umschließen müssen, um Zugriff auf das zu erhalten, was im Wesentlichen global ist?

Wie auch immer, wenn Sie sich ansehen, wie sie implementiert wurden <BrowserRouter>, ist es nur ein winziger Wrapper um die Geschichte .

Wir können diesen Verlauf herausziehen, damit wir ihn von überall importieren können. Der Trick besteht jedoch darin, dass beim serverseitigen Rendern und beim Versuch, importdas Verlaufsmodul zu verwenden, dies nicht funktioniert, da nur Browser-APIs verwendet werden. Dies ist jedoch in Ordnung, da wir normalerweise nur als Reaktion auf einen Klick oder ein anderes clientseitiges Ereignis umleiten. Daher ist es wahrscheinlich in Ordnung, es zu fälschen:

// history.js
if(__SERVER__) {
    module.exports = {};
} else {
    module.exports = require('history').createBrowserHistory();
}

Mithilfe von Webpack können wir einige Variablen definieren, damit wir wissen, in welcher Umgebung wir uns befinden:

plugins: [
    new DefinePlugin({
        '__SERVER__': 'false',
        '__BROWSER__': 'true', // you really only need one of these, but I like to have both
    }),

Und jetzt kannst du

import history from './history';

Von überall. Es wird nur ein leeres Modul auf dem Server zurückgegeben.

Wenn Sie diese magischen Variablen nicht verwenden möchten, müssen Sie sich nur requirein dem globalen Objekt befinden, in dem sie benötigt werden (in Ihrem Ereignishandler). importfunktioniert nicht, weil es nur auf der obersten Ebene funktioniert.

mpen
quelle
6
Verdammt, sie haben es so kompliziert gemacht.
Abhishek
4
Ich habe dir vollkommen zugestimmt. Dies ist so kompliziert für nur eine Navigation
Thai Tran
5

Ich denke, dass @rgommezz die meisten Fälle abdeckt, abzüglich eines, den ich für ziemlich wichtig halte.

// history is already a dependency or React Router, but if don't have it then try npm install save-dev history

import createHistory from "history/createBrowserHistory"

// in your function then call add the below 
const history = createHistory();
// Use push, replace, and go to navigate around.
history.push("/home");

Auf diese Weise kann ich einen einfachen Dienst mit Aktionen / Aufrufen schreiben, die ich aufrufen kann, um die Navigation von jeder gewünschten Komponente aus durchzuführen, ohne viel HoC für meine Komponenten auszuführen ...

Es ist nicht klar, warum noch niemand diese Lösung bereitgestellt hat. Ich hoffe, es hilft, und wenn Sie ein Problem damit sehen, lassen Sie es mich bitte wissen.

user3053247
quelle
4

Ich habe v4 jetzt seit ein paar Tagen getestet und .. Ich liebe es bis jetzt! Es macht nur nach einer Weile Sinn.

Ich hatte auch die gleiche Frage und fand, dass der Umgang damit wie folgt am besten funktioniert (und möglicherweise sogar so ist, wie es beabsichtigt ist). Es verwendet state, einen ternären Operator und <Redirect>.

Im Konstruktor ()

this.state = {
    redirectTo: null
} 
this.clickhandler = this.clickhandler.bind(this);

Im Render ()

render(){
    return (
        <div>
        { this.state.redirectTo ?
            <Redirect to={{ pathname: this.state.redirectTo }} /> : 
            (
             <div>
               ..
             <button onClick={ this.clickhandler } />
              ..
             </div>
             )
         }

Im Clickhandler ()

 this.setState({ redirectTo: '/path/some/where' });

Ich hoffe es hilft. Gib mir Bescheid.

jar0m1r
quelle
Gibt es Fallstricke bei dieser Methode? In meinem Projekt mit funktioniert nur, wenn ich den Status im Konstruktor festlege, kann ich von dort zu jeder gewünschten Seite umleiten. Aber wenn ich den Status auf Ereignis setze (Requisiten haben sich zum Beispiel geändert), wird die
Rendermethode
Die Gefahr besteht darin, dass die Historie ersetzt wird, sodass Sie nicht zurückschlagen können. Im Grunde ist dies keine gute Lösung.
Dannytenaglias
4

Ich hatte eine Weile damit zu kämpfen - etwas so Einfaches und doch so Kompliziertes, weil ReactJS nur eine völlig andere Art ist, Webanwendungen zu schreiben, es ist uns älteren Leuten sehr fremd!

Ich habe eine separate Komponente erstellt, um das Durcheinander zu abstrahieren:

// LinkButton.js

import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';

export default class LinkButton extends React.Component {

    render() {
        return (
            <Route render={({history}) => (
                <button {...this.props}
                       onClick={() => {
                           history.push(this.props.to)
                       }}>
                    {this.props.children}
                </button>
            )}/>
        );
    }
}

LinkButton.propTypes = {
    to: PropTypes.string.isRequired
};

Fügen Sie es dann Ihrer render()Methode hinzu:

<LinkButton className="btn btn-primary" to="/location">
    Button Text
</LinkButton>
mwieczorek
quelle
Ich finde diese Lösung sehr nützlich. Ich kopiere den Code. Lassen Sie mich wissen, dass Sie es auf Github setzen - ich werde es Ihnen direkt zuschreiben.
Abhinav Manchanda
3

Da es keinen anderen Weg gibt, mit diesem schrecklichen Design umzugehen, habe ich eine generische Komponente geschrieben, die den withRouter HOC- Ansatz verwendet. Das folgende Beispiel umschließt ein buttonElement, Sie können jedoch zu jedem anklickbaren Element wechseln, das Sie benötigen:

import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';

const NavButton = (props) => (
  <Button onClick={() => props.history.push(props.to)}>
    {props.children}
  </Button>
);

NavButton.propTypes = {
  history: PropTypes.shape({
    push: PropTypes.func.isRequired
  }),
  to: PropTypes.string.isRequired
};

export default withRouter(NavButton);

Verwendungszweck:

<NavButton to="/somewhere">Click me</NavButton>
Rodrigo
quelle
3
this.props.history.push("/url")

Wenn Sie this.props.history in Ihrer Komponente nicht verfügbar gefunden haben, versuchen Sie dies

import {withRouter} from 'react-router-dom'
export default withRouter(MyComponent)  
Shashwat Gupta
quelle
Vielen Dank!
QauseenMZ
1

Da ich manchmal lieber die Routen nach Anwendung als nach Schaltflächen wechsle, ist dies ein minimales Arbeitsbeispiel, das für mich funktioniert:

import { Component } from 'react'
import { BrowserRouter as Router, Link } from 'react-router-dom'

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

    /** @type BrowserRouter */
    this.router = undefined
  }

  async handleSignFormSubmit() {
    await magic()
    this.router.history.push('/')
  }

  render() {
    return (
      <Router ref={ el => this.router = el }>
        <Link to="/signin">Sign in</Link>
        <Route path="/signin" exact={true} render={() => (
          <SignPage onFormSubmit={ this.handleSignFormSubmit } />
        )} />
      </Router>
    )
  }
}
piotr_cz
quelle
0

Für diejenigen unter Ihnen, die eine Umleitung benötigen, bevor sie einen Router mit React Routeroder vollständig umleiten React Router Domkönnen. Sie können eine Umleitung bereitstellen, indem Sie einfach auf das Verlaufsobjekt zugreifen und einen neuen Status in Ihrem Konstruktor von darauf verschieben app.js. Folgendes berücksichtigen:

function getSubdomain(hostname) {
    let regexParse = new RegExp('[a-z\-0-9]{2,63}\.[a-z\.]{2,5}$');
    let urlParts = regexParse.exec(hostname);
    return hostname.replace(urlParts[0], '').slice(0, -1);
}

class App extends Component {

    constructor(props) {
        super(props);


        this.state = {
            hostState: true
        };

        if (getSubdomain(window.location.hostname).length > 0) {
            this.state.hostState = false;
            window.history.pushState('', '', './login');
        } else {
            console.log(getSubdomain(window.location.hostname));
        }

    }


    render() {
        return (

            <BrowserRouter>
                {this.state.hostState ? (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                        <Route path="/" component={PublicContainer}/>
                    </div>
                ) : (
                    <div>
                        <Route path="/login" component={LoginContainer}/>
                    </div>
                )

                }
            </BrowserRouter>)
    }


}

Hier möchten wir die Ausgaberouten abhängig von einer Subdomain ändern, indem wir mit dem Verlaufsobjekt interagieren, bevor die Komponente gerendert wird. Wir können effektiv umleiten, während unsere Routen weiterhin intakt bleiben.

window.history.pushState('', '', './login');
li x
quelle