Programmgesteuert mit dem React Router navigieren


1430

Mit react-routerkann ich das LinkElement verwenden, um Links zu erstellen, die nativ vom Reaktionsrouter verarbeitet werden.

Ich sehe intern, dass es anruft this.context.transitionTo(...).

Ich möchte eine Navigation machen. Nicht von einem Link, sondern von einer Dropdown-Auswahl (als Beispiel). Wie kann ich das im Code machen? Was ist this.context?

Ich habe das NavigationMixin gesehen, aber kann ich das ohne machen mixins?


26
@SergioTapia denken Sie daran, dass diese Frage eine Hauptversion von React-Router, eine Hauptversion von React und eine Hauptversion von Javascript umfasst
George Mauer

5
Hier ist ein Link zum Tutorial in den offiziellen Dokumenten von React
chitzui

4
Sie könnten diese Antwort überprüfen stackoverflow.com/questions/44127739/…
Shubham Khatri

4
Ich bin froh, dass du das beantwortet hast, aber ich bin traurig, dass es so kompliziert sein muss. Das Navigieren in einer Web-App sollte einfach und gut dokumentiert sein. VueJS macht es trivial. Jede Komponente erhält die Router-Instanz automatisch injiziert. Es gibt einen klar definierten Abschnitt dafür in ihren Dokumenten. router.vuejs.org/guide/essentials/navigation.html Ich mag React für viele Dinge, aber es ist manchmal so kompliziert. </ rant>
Colefner

7
@ GeorgeMauer Du hast recht. Darum geht es in dieser Community nicht. Es geht darum, Fragen zu beantworten und nicht über Frameworks zu streiten. Danke für die Erinnerung.
Colefner

Antworten:


1433

Reagieren Sie auf Router v5.1.0 mit Hooks

useHistoryIn React Router> 5.1.0 gibt es einen neuen Hook, wenn Sie React> 16.8.0 und Funktionskomponenten verwenden.

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

Reagiere auf Router v4

In Version 4 von React Router gibt es drei Ansätze für das programmatische Routing innerhalb von Komponenten.

  1. Verwenden Sie die withRouterKomponente höherer Ordnung.
  2. Verwenden Sie Komposition und rendern Sie a <Route>
  3. Verwenden Sie die context.

React Router ist meistens ein Wrapper um die historyBibliothek. historyErledigt die Interaktion mit den Browsern window.historyfür Sie mit den Browser- und Hash-Historien. Es bietet auch einen Speicherverlauf, der für Umgebungen ohne globalen Verlauf nützlich ist. Dies ist besonders nützlich bei der Entwicklung mobiler Apps ( react-native) und beim Testen von Einheiten mit Node.

Eine historyInstanz verfügt über zwei Navigationsmethoden: pushund replace. Wenn Sie sich das historyals Array von besuchten Standorten pushvorstellen, fügen Sie dem Array einen neuen Standort hinzu und replaceersetzen den aktuellen Standort im Array durch den neuen. Normalerweise möchten Sie die pushMethode beim Navigieren verwenden.

In früheren Versionen von Router Reaktion, hatten Sie eine eigene erstellen historyInstanz, sondern in v4 das <BrowserRouter>, <HashRouter>und <MemoryRouter>Komponenten wird eine Browser, Hash und Speicher - Instanzen für Sie erstellen. React Router stellt die Eigenschaften und Methoden der historyIhrem Router zugeordneten Instanz über den Kontext unter dem routerObjekt zur Verfügung.

1. Verwenden Sie die withRouterKomponente höherer Ordnung

Die withRouterKomponente höherer Ordnung injiziert das historyObjekt als Requisite der Komponente. Auf diese Weise können Sie auf die Methoden pushund zugreifen replace, ohne sich mit den Methoden befassen zu müssen 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. Verwenden Sie Komposition und rendern Sie a <Route>

Die <Route>Komponente dient nicht nur zum Abgleichen von Standorten. Sie können eine weglose Route rendern , die immer mit dem aktuellen Standort übereinstimmt . Die <Route>Komponente übergibt dieselben Requisiten wie withRouter, sodass Sie historyüber die historyRequisite auf die Methoden zugreifen können .

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

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

3. Verwenden Sie den Kontext *

Aber du solltest es wahrscheinlich nicht

Die letzte Option sollten Sie nur verwenden, wenn Sie mit dem Kontextmodell von React vertraut sind (die Kontext-API von React ist ab Version 16 stabil).

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 und 2 sind die am einfachsten zu implementierenden Optionen. In den meisten Anwendungsfällen sind sie die besten Wetten.


24
Ich habe versucht, Methode 1 auf diese Weise zu verwenden. WithRouter (({history}) => {console.log ("hhhhhhhh"); history.push ('/ bets')}); Aber es hat nie mit Router 4
funktioniert

57
WAS!? Ich kann nur verwenden, withRouteranstatt historyalle meine Komponenten weiterzugeben? Gahh, ich muss mehr Zeit damit verbringen, Dokumente zu lesen ...
Hallojeffhall

18
Wie können Sie einfach ausführen, history.push('/new-location')ohne dieses Verhalten an eine Schaltfläche oder ein anderes DOM-Element anzuhängen?
Neil

4
Wurffehler alsUnexpected use of 'history' no-restricted-globals
Pardeep Jain

18
contextist ab Reaktion 16 nicht mehr experimentell.
Tryse

920

React-Router 5.1.0+ Antwort (mit Hooks und React> 16.8)

Sie können den neuen useHistoryHook für Funktionskomponenten verwenden und programmgesteuert navigieren:

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

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

React-Router 4.0.0+ Antwort

Verwenden Sie in 4.0 und höher den Verlauf als Requisite Ihrer Komponente.

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

HINWEIS: this.props.history ist nicht vorhanden, falls Ihre Komponente nicht von gerendert wurde <Route>. Sie sollten <Route path="..." component={YourComponent}/>this.props.history in YourComponent verwenden

React-Router 3.0.0+ Antwort

Verwenden Sie in Version 3.0 und höher den Router als Requisite Ihrer Komponente.

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

React-Router 2.4.0+ Antwort

Verwenden Sie in Version 2.4 und höher eine Komponente höherer Ordnung, um den Router als Requisite Ihrer Komponente zu erhalten.

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

Diese Version ist abwärtskompatibel mit 1.x, sodass kein Upgrade-Handbuch erforderlich ist. Nur die Beispiele durchzugehen, sollte gut genug sein.

Wenn Sie jedoch zum neuen Muster wechseln möchten, befindet sich im Router ein browserHistory-Modul, auf das Sie zugreifen können

import { browserHistory } from 'react-router'

Jetzt haben Sie Zugriff auf Ihren Browserverlauf, sodass Sie beispielsweise Push, Ersetzen usw. ausführen können.

browserHistory.push('/some/path')

Weiterführende Literatur: Geschichten und Navigation


React-Router 1.xx Antwort

Ich werde nicht auf die Aktualisierung von Details eingehen. Sie können dies im Upgrade-Handbuch nachlesen

Die wichtigste Änderung bei dieser Frage ist der Wechsel vom Navigationsmixin zum Verlauf. Jetzt wird die Browser-Verlaufs-API verwendet, um die Route zu ändern, sodass wir sie pushState()von nun an verwenden werden.

Hier ist ein Beispiel mit Mixin:

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

Beachten Sie, dass dies Historyaus einem Rackt / History- Projekt stammt. Nicht vom React-Router selbst.

Wenn Sie Mixin aus irgendeinem Grund nicht verwenden möchten (möglicherweise aufgrund der ES6-Klasse), können Sie auf den Verlauf zugreifen, den Sie vom Router erhalten this.props.history. Es ist nur für die von Ihrem Router gerenderten Komponenten zugänglich. Wenn Sie es also in untergeordneten Komponenten verwenden möchten, muss es als Attribut über übergeben werden props.

Weitere Informationen zur neuen Version finden Sie in der Dokumentation zu 1.0.x.

Hier ist eine Hilfeseite speziell zum Navigieren außerhalb Ihrer Komponente

Es wird empfohlen, sich eine Referenz zu schnappen history = createHistory()und diese aufzurufen replaceState.

React-Router 0.13.x Antwort

Ich hatte das gleiche Problem und konnte die Lösung nur mit dem Navigationsmixin finden, das mit dem React-Router geliefert wird.

So habe ich es gemacht

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

Ich konnte anrufen, transitionTo()ohne darauf zugreifen zu müssen.context

Oder probieren Sie den schicken 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

Hinweis: Wenn Sie Redux verwenden, gibt es ein anderes Projekt namens React-Router-Redux , das Ihnen Redux-Bindungen für ReactRouter bietet und dabei den gleichen Ansatz wie React-Redux verwendet

React-Router-Redux verfügt über einige Methoden, die eine einfache Navigation innerhalb von Aktionserstellern ermöglichen. Diese können besonders nützlich sein für Benutzer mit vorhandener Architektur in React Native, die dieselben Muster in React Web mit minimalem Aufwand für die Boilerplate verwenden möchten.

Erforschen Sie die folgenden Methoden:

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

Hier ist ein Anwendungsbeispiel mit 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
Ich verwende, v2.4.0aber der erwähnte Ansatz funktioniert bei mir nicht, meine App wird überhaupt nicht gerendert und die Konsole wird ausgegeben: Uncaught TypeError: (0 , _reactRouter.withRouter) is not a functionHier ist der Link zu meinem SO-Beitrag: stackoverflow.com/questions/37306166/…
nburk

7
Dies sollte die akzeptierte Antwort sein, die akzeptierte ist ein bisschen chaotisch und sehr alt. @GiantElk Ich habe es wie in der Antwort für die Version beschrieben funktioniert 2.6.0.
JMac

2
Ist dieser Ansatz immer noch der empfohlene Weg für die Version 3.0.x? Viele Leute scheinen den contextWeg zu benutzen .
Velop

6
In 4.0 existiert this.props.history nicht. Was ist los?
Nicolas S.Xu

4
@ NicolasS.Xu this.props.historyexistiert nicht für den Fall, dass Ihre Komponente nicht von gerendert wurde <Route>. Sie sollten verwenden <Route path="..." component={YourComponent}/>, um this.props.historyin zu haben YourComponent.
Vogdb

508

React-Router v2

Für die neueste Version ( v2.0.0-rc5) wird empfohlen, direkt auf den Verlaufssingleton zu klicken. Sie können dies in Aktion im Dokument Navigieren außerhalb von Komponenten sehen .

Relevanter Auszug:

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

Bei Verwendung der neueren API-Router reagieren, müssen Sie die Verwendung von die machen historyaus , this.propswenn innerhalb der Komponenten so:

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

Es bietet auch, pushStateaber das ist pro protokollierten Warnungen veraltet.

Bei Verwendung react-router-reduxbietet es eine pushFunktion, die Sie wie folgt versenden können:

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

Dies kann jedoch nur verwendet werden, um die URL zu ändern, nicht um tatsächlich zur Seite zu navigieren.


15
Vergessen Sie nicht, dass die neuere API nicht verwendet, import { browserHistory } from './react-router'sondern mithilfe von Verlauf erstellt import createBrowserHistory from 'history/lib/createBrowserHistory'. Später können Sie historyvon den Komponenten Requisiten zugreifen :this.props.history('/some/path')
Ricardo Pedroni

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

7
React-Router-Redux pushändert nur die URL, ändert die Seite jedoch nicht. Um beides zu tun, importieren Sie browserHistoryaus react-routerund verwenden Sie browserHistory.push('/my-cool-path'). Leider ist dies nicht sehr leicht zu finden. github.com/reactjs/react-router/blob/master/docs/guides/…
Andrew Samuelsen

4
Ich verwende this.props.history.push ('/'), aber nur die URL wird geändert ... Hier findet kein tatsächliches Routing statt. Was vermisse ich?
rgcalsaverini

2
Ich mein nehmen nur hochgeladen auf , wie in neuesten programmatisch navigieren react-routerv4
spik3s

56

So machen Sie das react-router v2.0.0mit ES6 . react-routerhat sich von Mixins entfernt.

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
Ich glaube, die aktuelle Empfehlung ist, den historyvon @Bobby angegebenen Singleton zu verwenden . Sie könnten verwenden, context.routeraber Sie machen es wirklich schwierig, diese Komponenten einem Komponententest zu unterziehen, da die Instanziierung nur dieser Komponente dies nicht im Kontext hat.
George Mauer

2
@ GeorgeMauer Ich denke, es hängt davon ab, wo der Code läuft. Gemäß den React-Dokumenten wird die Verwendung von context.router empfohlen, wenn es auf dem Server ausgeführt wird. github.com/reactjs/react-router/blob/master/upgrade-guides/…
KumarM

50

React-Router 4.x Antwort:

Am Ende möchte ich ein einzelnes Verlaufsobjekt haben, das ich auch außerhalb von Komponenten tragen kann. Was ich gerne mache, ist, eine einzelne Datei history.js zu haben, die ich bei Bedarf importiere, und sie einfach zu bearbeiten.

Sie müssen nur BrowserRouterzu Router wechseln und die Verlaufsstütze angeben. Dies ändert nichts für Sie, außer dass Sie über ein eigenes Verlaufsobjekt verfügen, das Sie nach Belieben bearbeiten können.

Sie müssen installieren Geschichte , die Bibliothek , die von react-router.

Anwendungsbeispiel, ES6-Notation:

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

BEARBEITEN 16. April 2018:

Wenn Sie von einer Komponente aus navigieren müssen, die tatsächlich von einer RouteKomponente gerendert wurde , können Sie auch über Requisiten wie folgt auf den Verlauf zugreifen:

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
Außer in den React Router-Dokumenten heißt es, dass Sie in den meisten Fällen nicht Routerstattdessen verwenden sollten BrowserRouter. BrowserRoutererstellt und pflegt das historyObjekt für Sie. Sie sollten nicht standardmäßig Ihre eigenen erstellen, nur wenn Sie ["eine tiefe Integration mit State-Management-Tools wie Redux benötigen."] Reacttraining.com/react-router/web/api/Router
bobbyz

2
Das habe ich im Laufe der Zeit und Erfahrung gelernt. Obwohl es normalerweise eine gute Praxis ist, die Standardeinstellung zu verwenden this.props.history, habe ich noch keine Lösung gefunden, die mir dabei helfen kann, so etwas in einer Klasse zu tun, die keine Komponente oder ein anderes Tool ist, das nicht als React-Komponente erstellt wurde Sie können Requisiten weitergeben. Vielen Dank für Ihr Feedback :)
Eric Martin

44

Für diesen, der die Serverseite nicht kontrolliert und aus diesem Grund den Hash-Router v2 verwendet:

Platzieren Sie Ihren Verlauf in einer separaten Datei (z. B. app_history.js ES6):

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

export default appHistory;

Und überall einsetzen!

Ihr Einstiegspunkt für den React-Router (app.js ES6):

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

Ihre Navigation in einer beliebigen Komponente (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
Vielen Dank. Vielleicht fehlt mir etwas. Ist das nicht genau das Gleiche wie die beiden besten Antworten?
George Mauer

2
Wenn Sie die "Hash" -Navigation verwenden, müssen Sie in "React-Router" v2 das zusätzliche Modul "Verlauf" installieren (wenn Sie seltsame Hash-Abfragen vermeiden möchten), und anstatt browserHistory zu verwenden, müssen Sie useRouterHistory (createHashHistory) verwenden ( {queryKey: false}). Dies ist der Hauptgrund, warum ich dies gepostet habe. Ich habe gezeigt, wie man mit der Hash-Geschichte navigiert.
Alexey Volodko

1
Oh, ich verstehe, du hast recht. Ich bin nicht mehr in diesem Projekt, aber ich denke, der bevorzugte Weg ist, historyjetzt für beide Ansätze zu verwenden
George Mauer

4
Warum ist diese Antwort nicht die beste? Warum sollten Sie sich mit Context- oder HOC- oder Event-Prototypen die Mühe machen, warum nicht einfach den Verlauf importieren und überall dort verwenden, wo es uns gefällt?
Ich

@storm_buster gibt es keinen Kompromiss. Wir haben ES6-Module und sollten sie verwenden! Dies ist ein typisches Beispiel für die Verwendung Ihres Tools (in diesem Fall reagieren) für alles - auch für Dinge, für die Sie sie nicht wirklich verwenden möchten.
Capaj

40

Reagiere auf Router V4

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.


Dies ist die beste Antwort, die ich gefunden habe. Die Verwendung withRouterhat nicht funktioniert, als sie sich bereits auf der Route befand, die neu geladen wird. In unserem Fall mussten wir selektiv entweder tun setState(verursachen return <Redirect>), wenn wir bereits auf der Route waren oder history.push()von woanders.
Karmakaze

Sehr, sehr klug. Und doch sehr einfach. Tks. Ich habe es in ReactRouterTable verwendet, da ich den Klick auf die gesamte Zeile verarbeiten wollte. Wird bei onRowClick verwendet, um den Status festzulegen. setState ({navigieren zu: "/ path /" + row.uuid});
Lovato

Dies ist eine kugelsichere Antwort.
Nitin Jadhav

31

Warnung: Diese Antwort gilt nur für ReactRouter-Versionen vor 1.0

Ich werde diese Antwort nachher mit 1.0.0-rc1 Anwendungsfällen aktualisieren!

Sie können dies auch ohne Mixins tun.

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

Das Problem mit Kontexten ist, dass es nur zugänglich ist, wenn Sie das contextTypesfür die Klasse definieren.

Was den Kontext betrifft, handelt es sich um ein Objekt wie Requisiten, das vom Elternteil an das Kind weitergegeben wird, aber implizit weitergegeben wird, ohne dass Requisiten jedes Mal neu deklariert werden müssen. Siehe https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


26

Ich habe mindestens 10 Möglichkeiten ausprobiert, bevor etwas richtig funktioniert hat!

Die withRouterAntwort von @Felipe Skinner war für mich etwas überwältigend und ich war mir nicht sicher, ob ich neue Klassennamen "ExportedWithRouter" erstellen wollte.

Hier ist der einfachste und sauberste Weg, dies zu tun, z. B. der aktuelle React-Router 3.0.0 und ES6:

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

oder, wenn es nicht Ihre Standardklasse ist, exportieren Sie wie folgt:

withRouter(Example);
export { Example };

Beachten Sie, dass in 3.xx die <Link>Komponente selbst verwendet wird router.push, sodass Sie alles übergeben können, was Sie dem <Link to=Tag übergeben würden, z.

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

1
Es funktioniert völlig gut. Antwortet aber 200 OKstatt 30xCode. Wie kann ich dieses Problem beheben?
Muhammad Ateeq Azam

1
Nicht sicher. Das ist mir nie aufgefallen, weil es keine externe Anfrage ist - es ist nur Ihr Browser, der den Code der Seite verwendet, um zu ändern, was auf der Seite ist. Sie können jederzeit eine manuelle Javascript-Umleitung durchführen, wenn Sie dies bevorzugen.
Ben Wheeler

1
es kann auch mit @withRouter als Klassendekorateur verwendet werden ... passt hervorragend zu mobx
Dan

21

Um die Navigation programmgesteuert durchzuführen , müssen Sie einen neuen Verlauf in die props.history in Ihrem Verzeichnis verschiebencomponent , damit so etwas die Arbeit für Sie erledigen kann:

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

Bitte schreiben Sie die Version von React-Router
Ash

19

Für ES6 + React-Komponenten hat die folgende Lösung für mich funktioniert.

Ich folgte Felippe Skinner, fügte aber eine End-to-End-Lösung hinzu, um Anfängern wie mir zu helfen.

Unten sind die Versionen, die ich verwendet habe:

"React-Router": "^ 2.7.0"

"reagieren": ^ 15.3.1

Unten ist meine Reaktionskomponente, in der ich die programmatische Navigation mit dem Reaktionsrouter verwendet habe:

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;

Unten ist die Konfiguration für meinen 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

Vielleicht nicht der beste Ansatz, aber ... Mit dem React-Router v4 könnte das folgende Typoskript für einige eine Idee geben.

In der gerenderten Komponente unten, zum Beispiel LoginPage, routerObjekt zugänglich ist und rufen Sie einfach router.transitionTo('/homepage')zu navigieren.

Navigationscode wurde entnommen aus .

"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
Warum verwenden Sie nicht withRouter und browserHistory?
Erwin Mayer

1
@Erwin Die API unterscheidet sich in Version 4. Siehe diese github.com/ReactTraining/react-router/issues/3847 .
McKu

1
@mcku Woher hast du deine Typoskript-DTS-Datei für React-Router v4?
Jmathew

1
@jmathew Ich habe keine Typdefinitionen für
React

16

In React-Router v4 und ES6

Sie können withRouterund verwenden 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
Bereits in mehreren anderen Antworten erwähnt (einschließlich ausführlich in der oberen Antwort)
George Mauer

13

Zur Verwendung withRoutermit einer klassenbasierten Komponente, versuchen Sie so etwas wie dies unten. Vergessen Sie nicht, die zu verwendende Exportanweisung zu ändern 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

basierend auf der vorherigen Antwort
von José Antonio Postigo und Ben Wheeler
die Neuheit? wird in geschrieben werden Typoskript
und die Verwendung von Dekorateure
oder statische Eigenschaft / Feld

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

mit was auch immer npm heute installiert. "React-Router": "^ 3.0.0" und
"@ types / React-Router": "^ 2.0.41"


11

Mit React-Router v4 am Horizont gibt es jetzt eine neue Möglichkeit, dies zu tun.

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 ist eine Beispiel-App, die zeigt, wie der React-Router verwendet / aktualisiert wird. Sie enthält Beispielfunktionstests, die in der App navigieren.


5
Dies ist ideal für die Navigation über die Renderfunktion, obwohl ich mich frage, wie ich von einem Lifecycle-Hook oder Redux aus navigieren kann.
Ruben Martinez Jr.

11

In React Router v4. Ich folge diesen beiden Wegen, um programmgesteuert zu routen.

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

Nummer zwei

Ersetzt den aktuellen Eintrag im Verlaufsstapel

Um Verlauf in Requisiten zu erhalten, müssen Sie möglicherweise Ihre Komponente mit einwickeln

withRouter


Vielen Dank!! Beste Antwort
Taha Farooqui

9

Wenn Sie einen Hash- oder Browserverlauf verwenden, können Sie dies tun

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

2
hashHistory.push, gibt die Eigenschaft "Push" von undefined nicht lesen. Woher importieren Sie diese?
ArchNoob

{hashHistory} aus "React-Router" importieren; Sie können es so oben importieren.
Zaman Afzal

Ich verwende Ihr Codebeispiel aus meiner Redux-Saga-Datei und importiere es genau so, wie Sie es gesagt haben, und verwende es, aber ich erhalte weiterhin diesen TypeError.
ArchNoob

8

Mit der aktuellen React-Version (15.3) this.props.history.push('/location');funktionierte für mich, aber es zeigte die folgende Warnung:

browser.js: 49 Warnung: [React-Router] props.historyund context.historysind veraltet. Bitte benutzen context.router.

und ich habe es so gelöst context.router:

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
Dies funktioniert für V4. Nun ... nah ... es muss tatsächlich this.context.router.history.push ('/ back-location') sein;
Velohomme

7

React-Router V4

Wenn Sie Version 4 verwenden, können Sie meine Bibliothek (Shameless Plug) verwenden, in der Sie einfach eine Aktion auslösen und alles funktioniert!

dispatch(navigateTo("/aboutUs"));

Trippler


5

Diejenigen, die Probleme bei der Implementierung auf dem React-Router v4 haben.

Hier ist eine funktionierende Lösung für die Navigation durch die React-App aus Redux-Aktionen.

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 ODER Redux-Datei

import history from './history' 

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

Alles dank diesem Kommentar: ReactTraining gibt einen Kommentar heraus


4

Wenn Sie RR4 mit Redux durch React -Router-Redux koppeln , können Sie auch die Routing-Aktionsersteller von verwenden react-router-redux.

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)

Wenn Sie Redux Thunk / Saga verwenden, um den asynchronen Fluss zu verwalten, importieren Sie die oben genannten Aktionsersteller in Redux-Aktionen und haken Sie ein, um Komponenten mit mapDispatchToProps zu reagieren.


1
react-router-reduxwurde für eine lange Zeit veraltet / archiviert
Oligofren

4

Sie können den useHistoryHook auch in einer zustandslosen Komponente verwenden. Beispiel aus den Dokumenten.

import { useHistory } from "react-router"

function HomeButton() {
  const history = useHistory()

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

Hinweis: Haken wurden hinzugefügt react-router@5.1.0und erfordernreact@>=16.8


1
Guter Anruf, können Sie feststellen, auf welche Version von React-Router und React sich bezieht? Dies ist eine neue Änderung, die nicht immer verfügbar war
George Mauer

3

Die richtige Antwort war zum Zeitpunkt des Schreibens für mich

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

Sie müssen Ihrer Komponente jedoch PropTypes hinzufügen

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

Vergessen Sie nicht, PropTypes zu importieren

import PropTypes from 'prop-types';

Bitte notieren Sie sich die Version des React-Routers und was haben Sie vom React-Router importiert
Ash

Nichts zu importieren und dies ist die Version "React-Router": "^ 4.2.0"
Webmaster

3

Vielleicht nicht die beste Lösung, aber sie erledigt den Job:

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

Grundsätzlich ruft eine an eine Aktion gebundene Logik (in diesem Fall eine Nachlöschung) einen Auslöser für die Umleitung auf. Dies ist nicht ideal, da Sie Ihrem Markup einen DOM-Knoten-Trigger hinzufügen, damit Sie ihn bei Bedarf bequem aufrufen können. Außerdem interagieren Sie direkt mit dem DOM, was in einer React-Komponente möglicherweise nicht erwünscht ist.

Diese Art der Umleitung ist jedoch nicht so oft erforderlich. Ein oder zwei zusätzliche, versteckte Links in Ihrem Komponenten-Markup würden also nicht so weh tun, besonders wenn Sie ihnen aussagekräftige Namen geben.


Können Sie erklären, warum Sie dies jemals gegenüber der akzeptierten Lösung verwenden würden?
George Mauer

Es ist nur eine alternative Lösung für das diskutierte Problem. Wie bereits erwähnt, nicht ideal, aber für programmatische Weiterleitungen geeignet.
Neatsu

2

Dies funktionierte für mich, es waren keine speziellen Importe erforderlich:

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

Dies erfordert natürlich spezielle Importe - Ihre Komponente hat nicht nur von selbst historyhinzugefügt props. Das kommt von einem HoC, den Sie importieren müssten, um es zu verwenden (Komponenten, die direkt an gesendet werden, Routewerden automatisch von diesem HoC verpackt, aber dann benötigen Sie einen Import für Route...)
George Mauer

2

Verwenden Sie stattdessen Hookrouter, die moderne Alternative zum React-Router

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

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

Um die OP-Frage zum Verknüpfen über ein Auswahlfeld zu beantworten, können Sie Folgendes tun:

navigate('/about');

Zu Ihrer Information. Der Autor selbst nennt diese Bibliothek "Proof of Concept" und sie hat seit fast einem Jahr (Juni 2019) keine Aktivität mehr.
MEMark

@MEMark das liegt daran, dass es schon perfekt ist
StefanBob

Nun, die 38 offenen Ausgaben, zusammen mit der Tatsache, dass Version 2.0 laut Autor eine vollständige Neufassung sein wird, sagen etwas anderes.
MEMark

1

Für React Router v4 +

Angenommen, Sie müssen während des ersten Renderns (für das Sie die <Redirect>Komponente verwenden können) nicht navigieren. Dies tun wir in unserer App.

Definieren Sie eine leere Route, die null zurückgibt. Auf diese Weise erhalten Sie Zugriff auf das Verlaufsobjekt. Sie müssen dies auf der obersten Ebene tun, auf der Ihre Routerdefiniert ist.

Jetzt können Sie alle die Dinge tun , die auf getan werden kann Geschichte wie history.push(), history.replace(), history.go(-1)usw.!

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

React-Router-Dom: 5.1.2

  • Diese Seite hat 3 Seiten, die alle dynamisch im Browser gerendert werden.

  • Beachten Sie, dass React Router die URL beim Navigieren durch die Site auf dem neuesten Stand hält, obwohl die Seite nie aktualisiert wird. Dadurch bleibt der Browserverlauf erhalten, und es wird sichergestellt, dass Dinge wie die Schaltfläche "Zurück" und Lesezeichen ordnungsgemäß funktionieren

  • Ein Switch durchsucht alle untergeordneten Elemente und rendert das erste, dessen Pfad mit der aktuellen URL übereinstimmt. Verwenden Sie eine, wenn Sie mehrere Routen haben, aber jeweils nur eine davon rendern soll

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

Willkommen bei SO! Wenn Sie auf eine Frage mit so vielen Antworten antworten, versuchen Sie, Ihre Vorteile aufzuzeigen.
David García Bodego

Dies beantwortet auch nicht die Frage, wie es programmgesteuert aus imperativem js und nicht mit Markup gemacht werden soll.
George Mauer

1

In meiner Antwort gibt es also drei verschiedene Möglichkeiten, programmgesteuert zu einer Route umzuleiten. Einige der Lösungen wurden bereits vorgestellt, die folgenden konzentrierten sich jedoch nur auf Funktionskomponenten mit einer zusätzlichen Demo-Anwendung.

Verwenden der folgenden Versionen:

reagieren: 16.13.1

Reaktionsdom: 16.13.1

React -Router: 5.2.0

React -Router-Dom: 5.2.0

Typoskript: 3.7.2

Aufbau:

Die Lösung verwendet also zunächst HashRouterFolgendes:

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

Aus der Dokumentation über <HashRouter>:

A <Router>, das den Hash-Teil der URL verwendet (dh window.location.hash), um Ihre Benutzeroberfläche mit der URL synchron zu halten.

Lösungen:

  1. Verwenden <Redirect>zum Schieben mit useState:

In einer Funktionskomponente ( RedirectPushActionKomponente aus meinem Repository) können wir die useStateUmleitung verwenden. Ein schwieriger Teil ist, dass wir nach der Umleitung den redirectStatus wieder herstellen müssen false. Durch die Verwendung von setTimeOutmit 0Verzögerung warten wir , bis Commits Reagieren Redirectauf das DOM dann auf die Schaltfläche , um immer wieder beim nächsten Mal zu verwenden.

Nachfolgend finden Sie mein Beispiel:

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

Aus der <Redirect>Dokumentation:

Wenn Sie a <Redirect>rendern, navigieren Sie zu einem neuen Ort. Der neue Speicherort überschreibt den aktuellen Speicherort im Verlaufsstapel, wie dies bei serverseitigen Weiterleitungen (HTTP 3xx) der Fall ist.

  1. Mit useHistoryHaken:

In meiner Lösung gibt es eine Komponente namens UseHistoryAction, die Folgendes darstellt:

let history = useHistory();

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

Der useHistoryHook gibt uns Zugriff auf das Verlaufsobjekt, mit dem wir programmgesteuert navigieren oder Routen ändern können.

  1. Mit withRoutererhalten Sie die historyvon props:

Erstellt eine Komponente mit dem Namen WithRouterAction, wird wie folgt angezeigt:

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

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

export default withRouter(WithRouterAction);

Lesen aus der withRouterDokumentation:

Über die Komponente höherer Ordnung können Sie auf die historyEigenschaften des Objekts und die <Route>Übereinstimmung des nächsten zugreifen withRouter. withRoutervergehen aktualisiert match, locationund historyRequisiten , um die eingewickelt Komponente , wenn es macht.

Demo:

Zur besseren Darstellung habe ich ein GitHub-Repository mit diesen Beispielen erstellt. Nachfolgend finden Sie es:

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

Ich hoffe das hilft!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.