web-dev-qa-db-fra.com

L'appel asynchrone dans ComponentWillMount se termine après la méthode de rendu

J'essaie d'effectuer un appel asynchrone à une API dans la méthode ComponentWillMount. En effet, j'aimerais que la méthode render soit exécutée après la méthode composantWillMount car je dois passer props au composant de ma méthode render.

Voici mon code:

class TennisSearchResultsContainer extends React.Component {
  componentWillMount () {
    // TODO: Build markers for the map
    // TODO: Check courtsResults object and database for tennis court
    this.courtsMarkers = this.props.courtsResults.map((court) => {
      return new google.maps.Marker({
        position: new google.maps.LatLng(JSON.parse(court.LOC).coordinates[1], JSON.parse(court.LOC).coordinates[0]),
        title: court.NAME,
        animation: google.maps.Animation.DROP
      });
    });
  }
  render () {
    return <TennisSearchResults criterias={this.props.criterias} courtsMarkers={this.courtsMarkers} />;
  }
}

Je ne comprends donc pas pourquoi ma méthode de rendu ne semble pas attendre que l'appel asynchrone se termine et transmette des accessoires non définis à mon composant enfant ...

Ai-je raison? Et que dois-je faire pour résoudre ce problème? Quel est le moyen de gérer cela?

33
Clement Levesque

Vous devrez peut-être mieux comprendre le comportement asynchrone javascript. Async signifie "n'attendez pas". Que la tâche se produise en arrière-plan et que d'autres codes continuent de s'exécuter. Un bon moyen de gérer cela consiste à définir l'état de votre composant. Par exemple, lorsque vous entrez componentDidMount, définissez un état loading sur true. Ensuite, lorsque votre fonction asynchrone est terminée, définissez cet état sur false. Dans votre fonction render, vous pouvez alors afficher un message "chargement ..." ou les données.

Voici un code qui montre un exemple simplifié d'extraction de données asynchrone et comment vous pouvez gérer cela dans React. Ouvrez les outils de développement de votre navigateur et examinez la sortie de la console pour mieux comprendre le cycle de vie React).

EDIT: Le code a été mis à jour pour utiliser les nouvelles recommandations de cycle de vie React à compter d'avril 2018. En résumé, j'ai remplacé componentWillMount par le plus sûr componentDidMount.

Il peut sembler inefficace de mettre à jour l’état après le composant est déjà monté, car composant [~ # ~] l’a fait [~ # ~] mount 'implique correctement. Cependant, conformément à la documentation officielle React sur composantDidMount :

"Si vous devez charger des données à partir d'un point de terminaison distant, il s'agit d'un bon endroit pour instancier la requête réseau."

"L'appel de setState() dans cette méthode déclenchera un rendu supplémentaire, mais cela se produira avant que le navigateur ne mette à jour l'écran. Ceci garantit que même si la render() sera appelée deux fois dans ce cas, l'utilisateur ne verra pas l'état intermédiaire. "

Voici l'exemple de code complet:

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

    console.log('This happens 1st.');

    this.state = {
      loading: 'initial',
      data: ''
    };

  }

  loadData() {
    var promise = new Promise((resolve, reject) => { 
      setTimeout(() => {
        console.log('This happens 6th (after 3 seconds).');
        resolve('This is my data.');
      }, 3000);
    });

    console.log('This happens 4th.');

    return promise;
  }

  componentDidMount() {

    console.log('This happens 3rd.');

    this.setState({ loading: 'true' });
    this.loadData()
    .then((data) => {
      console.log('This happens 7th.');
      this.setState({
        data: data,
        loading: 'false'
      });
    });
  }  

  render() {

    if (this.state.loading === 'initial') {
      console.log('This happens 2nd - after the class is constructed. You will not see this element because React is still computing changes to the DOM.');
      return <h2>Intializing...</h2>;
    }


    if (this.state.loading === 'true') {
      console.log('This happens 5th - when waiting for data.');
      return <h2>Loading...</h2>;
    }

    console.log('This happens 8th - after I get data.');
    return (
      <div>
        <p>Got some data!</p>
        <p>{this.state.data}</p>
       </div>
    );
  }
}

ReactDOM.render(
  <MyComponent />,
  document.getElementsByClassName('root')[0]
);

Et voici le exemple de travail sur CodePen .

Enfin, je pense que cette image du moderne React cycle de vie créée par React le mainteneur Dan Abramov) est utile pour visualiser ce qui se passe et à quel moment. .

enter image description here

NOTEZ qu'à compter de React 16.4, ce diagramme de cycle de vie contient une petite imprécision: getDerivedStateFromProps est également appelé après setState ainsi que forceUpdate. Voir cet article officiel React blog sur le correction de bug pour getDerivedStateFromProps

This version interactive du diagramme React cycle de vie créé par Wojciech Maj vous permet de sélectionner React version> 16.04 avec le dernier comportement ( toujours exact à la date du React 16.8.6, 27 mars 2019). Cochez la case "Afficher les cycles de vie moins courants".

62
Todd Chaffee