it-swarm.com.de

Programmgesteuert mit Reaktiver Router V4 navigieren

Ich habe gerade react-router von v3 zu v4 ersetzt.
Ich bin mir jedoch nicht sicher, wie ich programmgesteuert in der Member-Funktion einer Component. D. H. In handleClick()-Funktion navigieren möchte. Ich möchte nach /path/some/where navigieren, nachdem ich einige Daten verarbeitet habe .

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

Ich kann solche Schnittstellen jedoch nicht in Version 4 finden.
Wie kann ich mit v4 navigieren?

256
Colin Witkamp

Der einfachste Weg, um es zu erledigen:

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

Hinweis:

  • Möglicherweise möchten Sie die historyprop von der übergeordneten Komponente an die Komponente übergeben, die die Aktion aufrufen soll, wenn sie nicht verfügbar ist.
140
Jikku Jose

Ich hatte ein ähnliches Problem bei der Migration zu React-Router v4, daher versuche ich unten, meine Lösung zu erklären.

Bitte betrachten Sie diese Antwort nicht als den richtigen Weg, um das Problem zu lösen. Ich denke, es besteht eine gute Chance, dass etwas besseres entsteht, da React Router v4 reifer wird und Beta verlässt (es existiert möglicherweise sogar und ich habe es gerade nicht entdeckt) .

Für den Kontext hatte ich dieses Problem, weil ich gelegentlich Redux-Saga verwende, um das Verlaufsobjekt programmgesteuert zu ändern (beispielsweise wenn sich ein Benutzer erfolgreich authentifiziert).

Sehen Sie sich in den React Router-Dokumenten die <Router>Komponente an und Sie können sehen, dass Sie die Möglichkeit haben, Ihr eigenes History-Objekt über eine Requisite zu übergeben. Das ist das Wesentliche der Lösung - wir liefern das History-Objekt an React-Router aus einem global -Modul.

Schritte:

  1. Installieren Sie das History-npm-Modul - yarn add historyodernpm install history --save
  2. erstellen Sie eine Datei mit dem Namen history.js in Ihrem Ordner App.js (dies war meine Präferenz)

    // src/history.js
    
    import createHistory from 'history/createBrowserHistory';
    export default createHistory();`
    
  3. Fügen Sie dieses Verlaufsobjekt Ihrer Routerkomponente wie folgt 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 Historienobjekt importieren: 

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

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

49
Alex Mann

TL; DR:

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

Die einfache und deklarative Antwort lautet, dass Sie <Redirect to={URL} Push={boolean} /> in Kombination mit setState() verwenden müssen.

Push: boolean - Wenn true, wird beim Umleiten ein neuer Eintrag in die Historie eingefügt, 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 mehr hier .

PS. Das Beispiel verwendet ES7 + Eigenschaftsinitialisierer , um den Status zu initialisieren. Sehen Sie hier sowie bei Interesse.

32
Lyubomir

Schritt 1: Es gibt nur eine Sache zu importieren: 

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

Schritt 2: Übergeben Sie in Ihrer Route die Historie:

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

Schritt 3: Die Geschichte wird als Teil der Requisiten in der nächsten Komponente akzeptiert. Sie können also einfach: 

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

Das war einfach und sehr mächtig.

7
cdi-meo

können auch einfach Requisiten verwenden: this.props.history.Push('new_url')

6
user1445685

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;
6
Kaya Toast

Meine Antwort ist vergleichbar mit Alex's . Ich bin mir nicht sicher, warum React-Router das so unnötig kompliziert gemacht hat. Warum sollte ich meine Komponente mit einem HoC umwickeln müssen, nur um Zugang zu dem zu erhalten, was im Wesentlichen ein globales ist? 

Wenn Sie einen Blick darauf werfen, wie sie <BrowserRouter> implementiert haben, ist dies nur ein kleiner Wrapper um history .

Wir können diese Geschichte etwas herausziehen, damit wir sie von überall importieren können. Der Trick ist jedoch, wenn Sie serverseitiges Rendering durchführen und versuchen, das Protokollmodul zu import zu verwenden, es funktioniert nicht, da es Browser-APIs verwendet. Dies ist jedoch in Ordnung, da wir normalerweise nur als Antwort 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();
}

Mit Hilfe von webpack können wir einige vars 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 lediglich require im globalen Objekt (in Ihrem Event-Handler), wo es benötigt wird. import funktioniert nicht, da dies nur auf oberster Ebene funktioniert.

5
mpen

Ich habe v4 schon ein paar Tage getestet und .. ich liebe es bis jetzt! Nach einer Weile macht es einfach Sinn.

Ich hatte auch die gleiche Frage und ich fand, dass der Umgang mit dem Folgenden am besten funktioniert (und vielleicht sogar so, 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.

4
jar0m1r

Da es keine andere Möglichkeit gibt, mit diesem schrecklichen Design umzugehen, habe ich eine generische Komponente geschrieben, die den Ansatz withRouterHOC verwendet. Im folgenden Beispiel wird ein button-Element umbrochen, 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>
3
Rodrigo

Ich hatte eine Weile mit diesem Problem 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 beseitigen:

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

Dann fügen Sie es Ihrer render()-Methode hinzu:

<LinkButton className="btn btn-primary" to="/location">
    Button Text
</LinkButton>
2
mwieczorek

Ich denke, @rgommezz deckt die meisten Fälle ab, die 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");

Dies erlaubt mir, einen einfachen Dienst mit Aktionen/Aufrufen zu schreiben, den ich anrufen kann, um die Navigation von jeder beliebigen Komponente aus durchzuführen, ohne viel auf meinen Komponenten zu tun. 

Es ist nicht klar, warum niemand zuvor diese Lösung bereitgestellt hat. Ich hoffe es hilft, und wenn Sie irgendwelche Probleme damit sehen, lass es mich wissen.

2
user3053247

Da ich manchmal lieber Routen nach Anwendung als nach Schaltflächen wechsle, ist dies ein minimales Funktionsbeispiel, 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>
    )
  }
}
1
piotr_cz

Für diejenigen, die vor der vollständigen Initialisierung eines Routers mithilfe von React Router oder React Router Dom eine Umleitung durchführen müssen. Sie können eine Weiterleitung bereitstellen, indem Sie einfach auf das History-Objekt zugreifen und einen neuen Status in Ihr Konstrukt von app.js eingeben. 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 Subdomäne ändern, indem wir mit dem History-Objekt interagieren, bevor die Komponente das Rendern ausführt, und wir können effektiv umleiten, während unsere Routen unverändert bleiben.

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