Question Naviguer par programme à l'aide du routeur de réaction


Avec react-router Je peux utiliser le Link élément pour créer des liens qui sont gérés nativement par le routeur de réaction.

Je vois en interne les appels this.context.transitionTo(...).

Je veux faire une navigation, mais pas à partir d'un lien, à partir d'une liste déroulante par exemple. Comment puis-je faire cela dans le code? Quel est this.context?

J'ai vu le Navigation mixin, mais puis-je le faire sans mixins?


775
2018-06-26 17:38


origine


Réponses:


React Router v4

Avec v4 de React Router, il existe trois approches que vous pouvez prendre pour le routage programmatique dans les composants.

  1. Utilisez le withRouter composant d'ordre supérieur.
  2. Utiliser la composition et rendre un <Route>
  3. Utilisez le context.

React Router est principalement un emballage autour du history bibliothèque. history gère l'interaction avec le navigateur window.history pour vous avec son navigateur et ses historiques de hachage. Il fournit également un historique de la mémoire utile pour les environnements n'ayant pas d'historique global. Ceci est particulièrement utile dans le développement d'applications mobiles (react-native) et tests unitaires avec Node.

UNE history instance a deux méthodes pour naviguer: push et replace. Si vous pensez à la history comme un tableau des lieux visités, push va ajouter un nouvel emplacement à la matrice et replace remplacera l'emplacement actuel dans le tableau par le nouveau. Typiquement, vous voulez utiliser le push méthode lorsque vous naviguez.

Dans les versions antérieures de React Router, vous deviez créer votre propre history par exemple, mais dans le v4 le <BrowserRouter>, <HashRouter>, et <MemoryRouter> Les composants créeront des instances de navigateur, de hachage et de mémoire pour vous. React Router fait les propriétés et les méthodes de la history instance associée à votre routeur disponible dans le contexte, sous la router objet.

1. Utilisez le withRouter composant d'ordre supérieur

le withRouter composant d'ordre supérieur va injecter le history objet comme un accessoire du composant. Cela vous permet d'accéder à push et replace méthodes sans avoir à faire face à la 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. Utiliser la composition et rendre un <Route>

le <Route> le composant n'est pas seulement pour les emplacements correspondants. Vous pouvez rendre un itinéraire sans chemin et il correspondra toujours à l'emplacement actuel. le <Route> composant passe les mêmes accessoires que withRouter, vous pourrez ainsi accéder à history méthodes à travers le history soutenir.

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

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

3. Utilisez le contexte *

* Mais vous ne devriez probablement pas

La dernière option est celle que vous ne devez utiliser que si vous vous sentez à l'aise de travailler avec React le contexte modèle. Bien que le contexte soit une option, il faut souligner que context est une API instable et que React a une section Pourquoi ne pas utiliser le contexte dans leur documentation. Alors utilisez à vos risques et périls!

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 et 2 sont les choix les plus simples à mettre en œuvre, donc pour la plupart des cas d'utilisation, ils sont vos meilleurs paris.


614
2018-02-08 18:39



React-Router 4.0.0+ Répondre

Dans 4.0 et ci-dessus, utilisez l'historique comme accessoire de votre composant.

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

React-Router 3.0.0+ Répondre

Dans 3.0 et ci-dessus, utilisez le routeur comme accessoire de votre composant.

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

React-Router 2.4.0+ Répondre

Dans 2.4 et ci-dessus, utilisez un composant d'ordre supérieur pour obtenir le routeur comme accessoire de votre composant.

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+ Répondre

Cette version est rétrocompatible avec 1.x, il n'y a donc pas besoin d'un Guide de mise à niveau. Juste en passant par les exemples devrait être assez bon.

Cela dit, si vous souhaitez passer au nouveau modèle, il y a un module browserHistory dans le routeur auquel vous pouvez accéder avec

import { browserHistory } from 'react-router'

Maintenant, vous avez accès à l'historique de votre navigateur, vous pouvez donc faire des choses comme pousser, remplacer, etc ...

browserHistory.push('/some/path')

En lire plus: Histoires et La navigation


React-Router 1.x.x Répondre

Je ne vais pas entrer dans les détails de mise à niveau. Vous pouvez lire à ce sujet dans le Mise à niveau Guide

Le principal changement à propos de la question ici est le passage de Navigation mixin à History. Maintenant, il utilise l'historique historyAPI pour changer de route, donc nous allons utiliser pushState() à partir de maintenant.

Voici un exemple utilisant Mixin:

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

Notez que ceci History vient de rackt / histoire projet. Pas de React-Router lui-même.

Si vous ne voulez pas utiliser Mixin pour une raison quelconque (peut-être à cause de la classe ES6), alors vous pouvez accéder à l'historique que vous obtenez du routeur this.props.history. Il sera uniquement accessible pour les composants rendus par votre routeur. Donc, si vous voulez l'utiliser dans n'importe quel composant enfant, il doit être transmis comme attribut via props.

Vous pouvez en savoir plus sur la nouvelle version à leur Documentation 1.0.x

Voici une page d'aide spécifique sur la navigation en dehors de votre composant

Il recommande de saisir une référence history = createHistory() et appeler replaceState sur ça.

React-Router 0.13.x Répondre

Je suis tombé sur le même problème et n'ai pu trouver la solution qu'avec le mixin de navigation fourni avec le routeur de réaction.

Voici comment je l'ai fait

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

J'étais capable d'appeler transitionTo() sans avoir besoin d'accéder .context

Ou vous pouvez essayer le fantaisie 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

Remarque: si vous utilisez Redux, il y a un autre projet appelé    React-Router-Redux ça te donne   redux bindings pour ReactRouter, en utilisant un peu la même approche que    Réagir-Redux Est-ce que

React-Router-Redux a quelques méthodes disponibles qui permettent une navigation simple depuis l'intérieur des créateurs d'actions. Ceux-ci peuvent être particulièrement utiles pour les personnes qui ont une architecture existante dans React Native, et ils souhaitent utiliser les mêmes modèles dans React Web avec un minimum de frais généraux.

Explorez les méthodes suivantes:

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

Voici un exemple d'utilisation, avec 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>

662
2018-06-26 17:49



React-Router v2

Pour la version la plus récente (v2.0.0-rc5), la méthode de navigation recommandée est en poussant directement sur l'historique singleton. Vous pouvez voir cela en action dans le Naviguer à l'extérieur du document Components.

Extrait pertinent:

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

Si vous utilisez la nouvelle API de routeur de réaction, vous devez utiliser le historyde this.props quand à l'intérieur des composants, donc:

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

Il offre également pushState mais cela est déconseillé par les avertissements enregistrés.

Si vous utilisez react-router-redux, il offre un push fonction que vous pouvez envoyer comme ça:

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

Cependant, ceci peut seulement être utilisé pour changer l'URL, pas pour réellement naviguer vers la page.


466
2018-01-18 20:32



Voici comment vous faites cela avec react-router v2.0.0 avec ES6. react-router s'est éloigné des mixins.

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
}

34
2018-01-22 20:46



Pour celui-ci, qui ne contrôle pas le côté serveur et à cause de cela utilise le routeur hash v2:

Place ton histoire dans un fichier séparé (par exemple, app_history.js ES6):

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

export default appHistory;

Et utilisez-le partout!

Votre point d'entrée pour le routeur de réaction (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"]'));

Votre navigation à l'intérieur de n'importe quel composant (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()
  }
})

25
2018-03-19 12:59



React-Router 4.x Réponse:

De mon côté, j'aime avoir un seul objet historique que je puisse porter même en dehors des composants. Ce que j'aime faire, c'est d'avoir un seul fichier history.js que j'importe à la demande, et que je manipule juste.

Vous devez juste changer BrowserRouter Router, et spécifiez l'historique prop. Cela ne change rien pour vous sauf que vous avez votre propre objet d'histoire que vous pouvez manipuler comme vous voulez.

Vous devez installer histoire, la bibliothèque utilisée par react-router.

Exemple d'utilisation, notation ES6:

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

EDIT le 16 avril 2018:

Si vous devez naviguer à partir d'un composant réellement rendu à partir d'un Route composant, vous pouvez également accéder à l'historique des accessoires, comme ça:

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

20
2018-06-06 22:14



Attention: cette réponse ne couvre que les versions de ReactRouter avant 1.0

Je vais mettre à jour cette réponse avec des cas d'utilisation 1.0.0-rc1 après!

Vous pouvez le faire sans mixins aussi.

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

Le gotcha avec les contextes est qu'il n'est pas accessible sauf si vous définissez le contextTypes sur la classe.

En ce qui concerne le contexte, c'est un objet, comme les accessoires, qui est transmis de parent à enfant, mais il est transmis implicitement, sans avoir à redéclarer les accessoires à chaque fois. Voir https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html


19
2018-06-30 06:14



J'ai essayé au moins 10 façons de le faire avant que quelque chose ne fonctionne correctement!

@Felipe Skinner's withRouter réponse était un peu écrasante pour moi, et je n'étais pas sûr que je voulais faire de nouveaux noms de classe "ExportedWithRouter".

Voici la manière la plus simple et la plus propre de le faire, dans le courant React-Router 3.0.0 et ES6:

React-Router 3.x.x avec 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);

ou, si ce n'est pas votre classe par défaut, exportez comme:

withRouter(Example);
export { Example };

Notez que dans 3.x.x, le <Link> composant lui-même utilise router.push, donc vous pouvez passer tout ce que vous passeriez le <Link to= tag, comme:

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

15
2017-11-30 14:02



Pour les composants ES6 + React, la solution suivante a fonctionné pour moi.

J'ai suivi Felippe skinner, mais j'ai ajouté une solution de bout en bout pour aider les débutants comme moi.

Voici les versions que j'ai utilisées:

"routeur-de-réaction": "^ 2.7.0"

"Réagir": "^ 15.3.1"

Ci-dessous est mon composant de réaction où j'ai utilisé la navigation programmatique en utilisant le routeur de réaction:

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;

Voici la configuration de mon routeur:

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

11
2017-09-12 22:00