Comment faire une redirection vers une autre route avec react-router?

95

J'essaie de faire un SIMPLE en utilisant react-router ( version ^ 1.0.3 ) pour rediriger vers une autre vue et je suis juste fatigué.

import React from 'react';
import {Router, Route, Link, RouteHandler} from 'react-router';


class HomeSection extends React.Component {

  static contextTypes = {
    router: PropTypes.func.isRequired
  };

  constructor(props, context) {
    super(props, context);
  }

  handleClick = () => {
    console.log('HERE!', this.contextTypes);
    // this.context.location.transitionTo('login');
  };

  render() {
    return (
      <Grid>
        <Row className="text-center">          
          <Col md={12} xs={12}>
            <div className="input-group">
              <span className="input-group-btn">
                <button onClick={this.handleClick} type="button">
                </button>
              </span>
            </div>
          </Col>
        </Row>
      </Grid>
    );
  }
};

HomeSection.contextTypes = {
  location() {
    React.PropTypes.func.isRequired
  }
}

export default HomeSection;

tout ce dont j'ai besoin est d'envoyer l'utilisation à '/ login' et c'est tout.

Que puis-je faire ?

erreurs dans la console:

Uncaught ReferenceError: PropTypes n'est pas défini

fichier avec mes itinéraires

// LIBRARY
/*eslint-disable no-unused-vars*/
import React from 'react';
/*eslint-enable no-unused-vars*/
import {Route, IndexRoute} from 'react-router';

// COMPONENT
import Application from './components/App/App';
import Contact from './components/ContactSection/Contact';
import HomeSection from './components/HomeSection/HomeSection';
import NotFoundSection from './components/NotFoundSection/NotFoundSection';
import TodoSection from './components/TodoSection/TodoSection';
import LoginForm from './components/LoginForm/LoginForm';
import SignupForm from './components/SignupForm/SignupForm';

export default (
    <Route component={Application} path='/'>
      <IndexRoute component={HomeSection} />
      <Route component={HomeSection} path='home' />
      <Route component={TodoSection} path='todo' />
      <Route component={Contact} path='contact' />
      <Route component={LoginForm} path='login' />
      <Route component={SignupForm} path='signup' />
      <Route component={NotFoundSection} path='*' />
    </Route>
);
Réagir
la source
Salut! Pouvez-vous publier vos routesdéfinitions, et également s'il y a une raison pour laquelle vous n'utilisez pas de Linkcomposant? Indiquez également les erreurs que vous obtenez.
aarosil
Au lieu de bouton <Link to="/login">Log In</Link>,?
aarosil
Quelle version de react-router utilisez-vous également? Le code de la redirection procédurale a changé parmi les versions principales.
mjhm
4
Pour le Uncaught ReferenceError, vous appelez en tant que PropTypes, mais vous ne l'importez pas, vous devez importer les PropTypes comme lui-même ou utiliserReact.PropTypes
aarosil
1
@JoshDavidMiller bon point mais je ne serai pas surpris du react-routerchangement d'API dans les 5 min .. haha ​​blague, mais juste partiellement
aarosil

Réponses:

33

Pour une réponse simple, vous pouvez utiliser le Linkcomposant from react-router, au lieu de button. Il existe des moyens de modifier l'itinéraire dans JS, mais il semble que vous n'en ayez pas besoin ici.

<span className="input-group-btn">
  <Link to="/login" />Click to login</Link>
</span>

Pour le faire par programme dans 1.0.x, procédez comme suit, dans votre fonction clickHandler:

this.history.pushState(null, 'login');

Tiré du document de mise à niveau ici

Vous devriez avoir this.historyplacé sur votre composant de gestionnaire d'itinéraire par react-router. S'il s'agit d'un composant enfant sous celui mentionné dans la routesdéfinition, vous devrez peut-être le transmettre plus loin

aarosil
la source
2
c'est une solution sympa, mais la raison pour laquelle je ne l'utilise pas, c'est parce que je dois d'abord faire comme une sorte de validation, donc je dois mettre cela dans une fonction, comme: if (true) { // redirect to login}c'est pourquoi je mets cela dans un onClick fonction
Réagissant le
5
Vous pouvez aussi le faire en JSX: {validation && <Link to="/login" />Click to login</Link>}. Si la validation est fausse, rien ne sera rendu.
aarosil
Je sais ce que vous voulez dire, mais j'ai besoin que le bouton soit là, si la validation est vraie, alors redirigez, sinon un message d'erreur devrait apparaître.
Réagissant le
@TheUnnamed J'ai mis à jour la réponse pour montrer comment faire dans JS
aarosil
1
> Uncaught TypeError: Impossible de lire la propriété « pushState » undefined
Réagissant
94

1) react-router> useHistorycrochet V5 :

Si vous avez React >= 16.8des composants fonctionnels, vous pouvez utiliser le useHistory hook de react-router .

import React from 'react';
import { useHistory } from 'react-router-dom';

const YourComponent = () => {
    const history = useHistory();

    const handleClick = () => {
        history.push("/path/to/push");
    }

    return (
        <div>
            <button onClick={handleClick} type="button" />
        </div>
    );
}

export default YourComponent;

2) react-router> V4 withRouterHOC:

Comme @ambar l'a mentionné dans les commentaires, React-router a changé sa base de code depuis sa V4. Voici les documentations - officielles , avec Routeur

import React, { Component } from 'react';
import { withRouter } from "react-router-dom";

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

export default withRouter(YourComponent);

3) React-router <V4 avec browserHistory

Vous pouvez obtenir cette fonctionnalité en utilisant react-router BrowserHistory. Code ci-dessous:

import React, { Component } from 'react';
import { browserHistory } from 'react-router';

export default class YourComponent extends Component {
    handleClick = () => {
        browserHistory.push('/login');
    };

    render() {
        return (
            <div>
                <button onClick={this.handleClick} type="button">
            </div>
        );
    };
}

4) Redux connected-react-router

Si vous avez connecté votre composant avec redux et que vous avez configuré le routeur connecté-react-router, tout ce que vous avez à faire est de this.props.history.push("/new/url");dire que vous n'avez pas besoin de withRouterHOC pour injecter historyles accessoires du composant.

// reducers.js
import { combineReducers } from 'redux';
import { connectRouter } from 'connected-react-router';

export default (history) => combineReducers({
    router: connectRouter(history),
    ... // rest of your reducers
});


// configureStore.js
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { routerMiddleware } from 'connected-react-router';
import createRootReducer from './reducers';
...
export const history = createBrowserHistory();

export default function configureStore(preloadedState) {
    const store = createStore(
        createRootReducer(history), // root reducer with router state
        preloadedState,
        compose(
            applyMiddleware(
                routerMiddleware(history), // for dispatching history actions
                // ... other middlewares ...
            ),
        ),
    );

    return store;
}


// set up other redux requirements like for eg. in index.js
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router';
import { ConnectedRouter } from 'connected-react-router';
import configureStore, { history } from './configureStore';
...
const store = configureStore(/* provide initial state if any */)

ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <> { /* your usual react-router v4/v5 routing */ }
                <Switch>
                    <Route exact path="/yourPath" component={YourComponent} />
                </Switch>
            </>
        </ConnectedRouter>
    </Provider>,
    document.getElementById('root')
);


// YourComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
...

class YourComponent extends Component {
    handleClick = () => {
        this.props.history.push("path/to/push");
    }

    render() {
        return (
          <div>
            <button onClick={this.handleClick} type="button">
          </div>
        );
      }
    };

}

export default connect(mapStateToProps = {}, mapDispatchToProps = {})(YourComponent);
Noushad
la source
3
On dirait que 'browserHistory' ne fait plus partie de react-router.
ambar
BrowserRouter n'a pas de fonction push
johnnyodonnell
@ambar @johnnyodonnell react-router-domfait
toinetoine
C'est la meilleure réponse. Vous devez marquer celui-ci comme le bon.
Solomon Bush
23

Comment faire une redirection vers une autre route avec react-router?

Par exemple, lorsqu'un utilisateur clique sur un lien, <Link to="/" />Click to route</Link>react-router recherchera /et vous pourrez utiliser Redirect toet envoyer l'utilisateur ailleurs comme la route de connexion.

À partir de la documentation pour ReactRouterTraining :

Le rendu <Redirect>permet d'accéder à un nouvel emplacement. Le nouvel emplacement remplacera l'emplacement actuel dans la pile d'historique, comme le font les redirections côté serveur (HTTP 3xx).

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

to: string, URL vers laquelle rediriger.

<Redirect to="/somewhere/else"/>

vers: objet, un emplacement vers lequel rediriger.

<Redirect to={{
  pathname: '/login',
  search: '?utm=your+face',
  state: { referrer: currentLocation }
}}/>
jtlindsey
la source
La solution fournie génère une erreur <Redirect> elements are for router configuration only and should not be rendered.
t1gor
10

La solution la plus simple pour le Web!

À jour 2020 a
confirmé travailler avec:

"react-router-dom": "^5.1.2"
"react": "^16.10.2"

Utilisez le useHistory()crochet!

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


export function HomeSection() {
  const history = useHistory();
  const goLogin = () => history.push('login');

  return (
    <Grid>
      <Row className="text-center">          
        <Col md={12} xs={12}>
          <div className="input-group">
            <span className="input-group-btn">
              <button onClick={goLogin} type="button" />
            </span>
          </div>
        </Col>
      </Row>
    </Grid>
  );
}
Scott Plunkett
la source
Excellent, je cherchais le moyen de le faire! Même si mon IDE indique l'avertissement "Impossible de résoudre le symbole ...", cela fonctionne!
Rafael Moni le
7

Avec react-router v2.8.1 (probablement d'autres versions 2.xx également, mais je ne l'ai pas testé), vous pouvez utiliser cette implémentation pour faire une redirection de routeur.

import { Router } from 'react-router';

export default class Foo extends Component {

  static get contextTypes() {
    return {
      router: React.PropTypes.object.isRequired,
    };
  }

  handleClick() {
    this.context.router.push('/some-path');
  }
}
Tom Van Rompaey
la source
parfois: this.context.router.history.push ('/ un-chemin');
象 嘉 道
4

La solution la plus simple est:

import { Redirect } from 'react-router';

<Redirect to='/componentURL' />
Jackkobec
la source
Mais j'obtiens une erreur: Invariant a échoué: vous ne devez pas utiliser <Redirect> en dehors d'un <Router>
Prateek Gupta
Avez-vous essayé d'envelopper?
Jackkobec le