163 votes

Comment utiliser Redirect dans le nouveau react-router-dom de Reactjs

J'utilise la dernière version du module react-router, nommé react-router-dom, qui est devenu le module par défaut lors du développement d'applications web avec React. Je veux savoir comment faire une redirection après une requête POST. J'ai fait ce code, mais après la requête, rien ne se passe. Je passe en revue sur le web, mais toutes les données sont sur les versions précédentes du react router, et pas avec la dernière mise à jour.

Code :

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'

import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';

class SignUpPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      errors: {},
      client: {
        userclient: '',
        clientname: '',
        clientbusinessname: '',
        password: '',
        confirmPassword: ''
      }
    };

    this.processForm = this.processForm.bind(this);
    this.changeClient = this.changeClient.bind(this);
  }

  changeClient(event) {
    const field = event.target.name;
    const client = this.state.client;
    client[field] = event.target.value;

    this.setState({
      client
    });
  }

  async processForm(event) {
    event.preventDefault();

    const userclient = this.state.client.userclient;
    const clientname = this.state.client.clientname;
    const clientbusinessname = this.state.client.clientbusinessname;
    const password = this.state.client.password;
    const confirmPassword = this.state.client.confirmPassword;
    const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };

    axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
      .then((response) => {
        this.setState({
          errors: {}
        });

        <Redirect to="/"/> // Here, nothings happens
      }).catch((error) => {
        const errors = error.response.data.errors ? error.response.data.errors : {};
        errors.summary = error.response.data.message;

        this.setState({
          errors
        });
      });
  }

  render() {
    return (
      <div className={styles.section}>
        <div className={styles.container}>
          <img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
          <SignUpForm 
            onSubmit={this.processForm}
            onChange={this.changeClient}
            errors={this.state.errors}
            client={this.state.client}
          />
          <Footer />
        </div>
      </div>
    );
  }
}

export default SignUpPage;

1 votes

Votre Redirect ressemble à JSX, pas à JS.

0 votes

Pouvez-vous fournir le code complet du composant

0 votes

Oui, j'utilise JSX. Je dois peut-être préciser. La demande POST est à l'intérieur d'un composant REACT qui fait la demande.

238voto

Vous devez utiliser setState pour définir une propriété qui rendra le <Redirect> à l'intérieur de votre render() méthode.

Par exemple

class MyComponent extends React.Component {
  state = {
    redirect: false
  }

  handleSubmit () {
    axios.post(/**/)
      .then(() => this.setState({ redirect: true }));
  }

  render () {
    const { redirect } = this.state;

     if (redirect) {
       return <Redirect to='/somewhere'/>;
     }

     return <RenderYourForm/>;
}

Vous pouvez également voir un exemple dans la documentation officielle : https://reacttraining.com/react-router/web/example/auth-workflow


Cela dit, je vous suggère de placer l'appel API dans un service ou autre. Ensuite, vous pourriez simplement utiliser la fonction history à l'itinéraire de manière programmatique. C'est ainsi que le intégration avec redux travaux.

Mais je suppose que vous avez vos raisons de procéder de cette façon.

1 votes

@sebastian sebald que voulez vous dire par : put the API call inside a service or something ?

1 votes

Le fait d'avoir un tel appel d'API (asynchrone) dans votre composant le rendra plus difficile à tester et à réutiliser. Il est généralement préférable de créer un service et de l'utiliser ensuite (par exemple) dans le composant componentDidMount . Ou mieux encore, créez un HOC qui "enveloppe" votre API.

7 votes

Attention, vous devez inclure Redirect pour l'utiliser en début de fichier : import { Redirect } from 'react-router-dom'.

42voto

Matthis Kohli Points 536

Voici un petit exemple en réponse au titre, car tous les exemples mentionnés sont compliqués à mon avis, tout comme l'exemple officiel.

Vous devez savoir comment transpiler es2015 et faire en sorte que votre serveur soit capable de gérer la redirection. Voici un extrait pour express. Vous trouverez plus d'informations à ce sujet ici .

Assurez-vous de le placer en dessous de toutes les autres routes.

const app = express();
app.use(express.static('distApp'));

/**
 * Enable routing with React.
 */
app.get('*', (req, res) => {
  res.sendFile(path.resolve('distApp', 'index.html'));
});

C'est le fichier .jsx. Remarquez comment le chemin le plus long vient en premier et devient plus général. Pour les chemins les plus généraux, utilisez l'attribut exact.

// Relative imports
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';

// Absolute imports
import YourReactComp from './YourReactComp.jsx';

const root = document.getElementById('root');

const MainPage= () => (
  <div>Main Page</div>
);

const EditPage= () => (
  <div>Edit Page</div>
);

const NoMatch = () => (
  <p>No Match</p>
);

const RoutedApp = () => (
  <BrowserRouter >
    <Switch>
      <Route path="/items/:id" component={EditPage} />
      <Route exact path="/items" component={MainPage} />          
      <Route path="/yourReactComp" component={YourReactComp} />
      <Route exact path="/" render={() => (<Redirect to="/items" />)} />          
      <Route path="*" component={NoMatch} />          
    </Switch>
  </BrowserRouter>
);

ReactDOM.render(<RoutedApp />, root);

1 votes

Cela ne fonctionne pas toujours. si vous avez une redirection de home/hello > home/hello/1 mais ensuite aller à home/hello et appuyez sur la touche entrée, il ne sera pas redirigé la première fois. une idée de la raison ??

0 votes

Je vous conseille d'utiliser "create-react-app" si possible et de suivre la documentation de react-router. Avec "create-react-app" tout fonctionne bien pour moi. Je n'ai pas été capable d'adapter ma propre application react au nouveau react-router.

6voto

KornholioBeavis Points 1031

Essayez quelque chose comme ça.

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Redirect } from 'react-router'

import SignUpForm from '../../register/components/SignUpForm';
import styles from './PagesStyles.css';
import axios from 'axios';
import Footer from '../../shared/components/Footer';

class SignUpPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      errors: {},
      callbackResponse: null,
      client: {
        userclient: '',
        clientname: '',
        clientbusinessname: '',
        password: '',
        confirmPassword: ''
      }
    };

    this.processForm = this.processForm.bind(this);
    this.changeClient = this.changeClient.bind(this);
  }

  changeClient(event) {
    const field = event.target.name;
    const client = this.state.client;
    client[field] = event.target.value;

    this.setState({
      client
    });
  }

  processForm(event) {
    event.preventDefault();

    const userclient = this.state.client.userclient;
    const clientname = this.state.client.clientname;
    const clientbusinessname = this.state.client.clientbusinessname;
    const password = this.state.client.password;
    const confirmPassword = this.state.client.confirmPassword;
    const formData = { userclient, clientname, clientbusinessname, password, confirmPassword };

    axios.post('/signup', formData, { headers: {'Accept': 'application/json'} })
      .then((response) => {
        this.setState({
          callbackResponse: {response.data},
        });
      }).catch((error) => {
        const errors = error.response.data.errors ? error.response.data.errors : {};
        errors.summary = error.response.data.message;

        this.setState({
          errors
        });
      });
  }

const renderMe = ()=>{
return(
this.state.callbackResponse
?  <SignUpForm 
            onSubmit={this.processForm}
            onChange={this.changeClient}
            errors={this.state.errors}
            client={this.state.client}
          />
: <Redirect to="/"/>
)}

  render() {
    return (
      <div className={styles.section}>
        <div className={styles.container}>
          <img src={require('./images/lisa_principal_bg.png')} className={styles.fullImageBackground} />
         {renderMe()}
          <Footer />
        </div>
      </div>
    );
  }
}

export default SignUpPage;

0 votes

Ça marche !, MERCI beaucoup. C'est une autre façon de faire.

0 votes

Vous ne devez pas faire de requêtes HTTP dans vos fichiers de composants.

0 votes

Pouvez-vous me dire ce que contient le fichier import SignUpForm from '../../register/components/SignUpForm'; ? J'essaie d'en tirer des enseignements. Bien que dans mon cas, j'utilise un formulaire redux.

1voto

sojan Points 42
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router-dom": "^4.2.2"

Pour naviguer vers une autre page (la page À propos dans mon cas), j'ai installé prop-types . Puis je l'importe dans le composant correspondant. Et j'ai utilisé this.context.router.history.push('/about') Et on y navigue.

Mon code est,

import React, { Component } from 'react';
import '../assets/mystyle.css';
import { Redirect } from 'react-router';
import PropTypes from 'prop-types';

export default class Header extends Component {   
    viewAbout() {
       this.context.router.history.push('/about')
    }
    render() {
        return (
            <header className="App-header">
                <div className="myapp_menu">
                    <input type="button" value="Home" />
                    <input type="button" value="Services" />
                    <input type="button" value="Contact" />
                    <input type="button" value="About" onClick={() => { this.viewAbout() }} />
                </div>
            </header>
        )
    }
}
Header.contextTypes = {
    router: PropTypes.object
  };

0voto

Morris S Points 541

Pour naviguer vers un autre composant, vous pouvez utiliser this.props.history.push('/main');

import React, { Component, Fragment } from 'react'

class Example extends Component {

  redirect() {
    this.props.history.push('/main')
  }

  render() {
    return (
      <Fragment>
        {this.redirect()}
      </Fragment>
    );
   }
 }

 export default Example

1 votes

React lance un avertissement : Warning: Cannot update during an existing state transition (such as within Rendu ). Render methods should be a pure function of props and state.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X