web-dev-qa-db-ger.com

Routenänderung mit React-Router erkennen

Ich muss einige Geschäftslogik abhängig vom Browserverlauf implementieren.

Was ich tun möchte, ist ungefähr so:

reactRouter.onUrlChange(url => {
   this.history.Push(url);
});

Gibt es eine Möglichkeit, einen Rückruf vom reaktionsrouter zu erhalten, wenn die URL aktualisiert wird?

44
Aris

Sie können die Funktion history.listen() verwenden, wenn Sie versuchen, die Routenänderung zu erkennen. Wenn Sie annehmen, dass Sie react-router v4 Verwenden, verpacken Sie Ihre Komponente mit withRouter HOC, um Zugriff auf die Stütze history zu erhalten.

history.listen() gibt eine unlisten -Funktion zurück. Sie würden dies verwenden, um unregister vom Hören abzuhalten.

Sie können Ihre Routen wie folgt konfigurieren

index.js

ReactDOM.render(
      <BrowserRouter>
            <AppContainer>
                   <Route exact path="/" Component={...} />
                   <Route exact path="/Home" Component={...} />
           </AppContainer>
        </BrowserRouter>,
  document.getElementById('root')
);

und dann in AppContainer.js

class App extends Component {

  componentWillMount() {
    this.unlisten = this.props.history.listen((location, action) => {
      console.log("on route change");
    });
  }
  componentWillUnmount() {
      this.unlisten();
  }
  render() {
     return (
         <div>{this.props.children}</div>
      );
  }
}
export default withRouter(App);

Aus der Geschichte docs :

Mit history.listen Können Sie nach Änderungen am aktuellen Standort suchen:

history.listen((location, action) => {
      console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`)
  console.log(`The last navigation action was ${action}`)
})

Das location-Objekt implementiert eine Teilmenge der window.location-Schnittstelle, einschließlich:

**location.pathname** - The path of the URL
**location.search** - The URL query string
**location.hash** - The URL hash fragment

Standorte können auch die folgenden Eigenschaften aufweisen:

location.state - Ein zusätzlicher Status für diesen Speicherort, der sich nicht in der URL befindet (unterstützt in createBrowserHistory und createMemoryHistory)

location.key - Eine eindeutige Zeichenfolge, die diesen Speicherort darstellt (unterstützt in createBrowserHistory und createMemoryHistory)

Die Aktion ist eine von Push, REPLACE, or POP, Abhängig davon, wie der Benutzer zur aktuellen URL gelangt ist.

Wenn Sie den React-Router v3 verwenden, können Sie history.listen() aus dem history -Paket verwenden, wie oben erwähnt, oder Sie können auch browserHistory.listen() verwenden.

Sie können Ihre Routen wie folgt konfigurieren und verwenden

import {browserHistory} from 'react-router';

class App extends React.Component {

    componentDidMount() {
          this.unlisten = browserHistory.listen( location =>  {
                console.log('route changes');

           });

    }
    componentWillUnmount() {
        this.unlisten();

    }
    render() {
        return (
               <Route path="/" onChange={yourHandler} component={AppContainer}>
                   <IndexRoute component={StaticContainer}  />
                   <Route path="/a" component={ContainerA}  />
                   <Route path="/b" component={ContainerB}  />
            </Route>
        )
    }
} 
67
Shubham Khatri

Wenn Sie das Objekt history global abhören möchten, müssen Sie es selbst erstellen und an Router übergeben. Dann können Sie es mit der listen() -Methode anhören:

// Use Router from react-router, not BrowserRouter.
import { Router } from 'react-router';

// Create history object.
import createHistory from 'history/createBrowserHistory';
const history = createHistory();

// Listen to history changes.
// You can unlisten by calling the constant (`unlisten()`).
const unlisten = history.listen((location, action) => {
  console.log(action, location.pathname, location.state);
});

// Pass history to Router.
<Router history={history}>
   ...
</Router>

Noch besser ist es, wenn Sie das Verlaufsobjekt als Modul erstellen, sodass Sie es problemlos überall dort importieren können, wo Sie es benötigen (z. B. import history from './history';

10
Fabian Schultz

Ich bin auf diese Frage gestoßen, als ich versucht habe, den ChromeVox-Bildschirmleser auf den oberen Rand des "Bildschirms" zu fokussieren, nachdem ich in einer React einseitigen App zu einem neuen Bildschirm navigiert habe. Grundsätzlich habe ich versucht, was zu emulieren Dies würde passieren, wenn diese Seite geladen würde, indem Sie einem Link zu einer neuen, vom Server gerenderten Webseite folgen.

Für diese Lösung sind keine Listener erforderlich. Sie verwendet withRouter() und die componentDidUpdate() -Lebenszyklusmethode, um einen Klick auszulösen, mit dem ChromeVox beim Navigieren zu einem neuen URL-Pfad auf das gewünschte Element fokussiert wird.


Implementierung

Ich habe eine "Screen" -Komponente erstellt, die um das React-Router-Switch-Tag gewickelt ist, das alle Apps-Bildschirme enthält.

<Screen>
  <Switch>
    ... add <Route> for each screen here...
  </Switch>
</Screen>

Screen.tsx Komponente

Hinweis: Diese Komponente verwendet React + TypeScript

import React from 'react'
import { RouteComponentProps, withRouter } from 'react-router'

class Screen extends React.Component<RouteComponentProps> {
  public screen = React.createRef<HTMLDivElement>()
  public componentDidUpdate = (prevProps: RouteComponentProps) => {
    if (this.props.location.pathname !== prevProps.location.pathname) {
      // Hack: setTimeout delays click until end of current
      // event loop to ensure new screen has mounted.
      window.setTimeout(() => {
        this.screen.current!.click()
      }, 0)
    }
  }
  public render() {
    return <div ref={this.screen}>{this.props.children}</div>
  }
}

export default withRouter(Screen)

Ich habe versucht, focus() anstelle von click() zu verwenden, aber durch Klicken auf wird ChromeVox angehalten, was gerade gelesen wird, und es wird erneut an der Stelle begonnen, an der ich es anweisen soll.

Hinweis für Fortgeschrittene: In dieser Lösung wird die Navigation <nav>, Die innerhalb der Screen-Komponente und nach dem Inhalt <main> Gerendert wird, visuell über dem main positioniert CSS order: -1;. Also im Pseudocode:

<Screen style={{ display: 'flex' }}>
  <main>
  <nav style={{ order: -1 }}>
<Screen>

Wenn Sie Gedanken, Kommentare oder Tipps zu dieser Lösung haben, fügen Sie bitte einen Kommentar hinzu.

1
Beau Smith