1
votes

"Impossible de lire la propriété d'undefined" dans React après la récupération et l'attente

Je suis nouveau dans React, et j'ai un problème avec la récupération:

J'ai fait un projet dans React où je dois chercher à partir de cinq URL différentes en fonction de la société sélectionnée par l'utilisateur. J'ai changé le code plusieurs fois, mais cela ne fonctionnera pas.

J'ai essayé avec componentDidMount (mais il n'est appelé qu'une seule fois, et je veux récupérer de nombreuses URL), avec "while (! This .state) "pour être occupé à attendre la récupération pour obtenir les données avant de les attribuer, etc.

Fonction de récupération:

Unhandled Rejection (TypeError): Cannot read property '3. Last Refreshed' of undefined:

  42 | setValues() {
> 43 |   day = this.state.data["Meta Data"]["3. Last Refreshed"];
     | ^  44 |   open = this.state.data["Time Series (Daily)"][day]["1. open"];
  45 |   higher = this.state.data["Time Series (Daily)"][day]["2. high"];

Fonction de définition des valeurs ce n'est pas si long):

render() {

    this.fetch_data();
    if(this.state.loading || !this.state || !this.state.data) {
      return <div>Loading :D...</div>
    } else {
      return (
        <div>
          <h2>Symbol: {symbol}</h2>
          <p>Url: {url}</p>
          <ul>
            <li>
              Open price: {open}
            </li>
            <li>
              Higher price: {higher}
            </li>
          </ul>
        </div>
      );
    }
  }

Fonction de rendu (également coupée):

setValues() {
    day = this.state.data["Meta Data"]["3. Last Refreshed"];
    open = this.state.data["Time Series (Daily)"][day]["1. open"];
    higher = this.state.data["Time Series (Daily)"][day]["2. high"];
  }

J'ai en fait fait la partie quand l'utilisateur sélectionne une société et le symbole (et l'url) change ... Mais le problème est que lorsque le programme veut accéder à this.state.data ["Time Series (Daily)"] [day] ["1. Open"]; , par exemple, il plante car il récupère et reçoit des données.

L'erreur dit:

async fetch_data() {
    var sel = this.props.select;
    symbol = companies[sel];
    url = 'https://www.alphavantage.co/query?function=' + func + '&symbol=' + symbol + '&outputsize=' + osize + '&apikey=' + api_key;
    var response = await fetch(url);
    var data = await response.json();

    while(!data);

    this.setState({data: data, loading: false });
    this.setValues();    
  }

L'application ne plante pas toujours, et elle affiche les résultats, mais le rendu Le composant continue d'appeler this.fetch_data () et il plante parce que parfois (comme 80% des fois) les données ne sont pas arrivées et j'essaye d'y accéder.


3 commentaires

Vous pouvez supprimer while (! Data); . Le mot-clé await s'assurera qu'une valeur est attribuée à data avant que setState ne soit appelé.


essayez ceci remplacez this.setValues ​​() par requestAnimationFrame (this.setValues)


Cela ne fonctionne pas non plus :(


3 Réponses :


0
votes

Je pense que c'est parce que vous appelez this.fetch_data (); rendu intérieur () cela signifie d'abord que vous n'avez aucune donnée dans votre état et après qu'il y ait une donnée, vous mettez à jour votre composant, donc vous appelez encore et encore this.fetch_data ();

Jetez un œil au cycle de vie des composants React: https: // code .likeagirl.io / comprendre-réagir-cycle-de-vie-des-composants-49bf4b8674de

autre chose inutile d'écrire while () car vous utilisez async await.


1 commentaires

Que puis-je faire alors pour appeler la fonction fetch uniquement lorsque le var "symbole" change sa valeur? Merci d'avoir répondu



0
votes

La raison de ce problème est que setState ( ) est asynchrone . Ce que cela signifie dans votre cas, c'est que les changements d'état effectués ici:

render() {

    this.fetch_data();
    if(this.state.loading || !this.state || !this.state.data) {
      return <div>Loading :D...</div>
    } else {

      /* Call to setValues() no longer needed */

      const day = this.state.data["Meta Data"]["3. Last Refreshed"];
      const open = this.state.data["Time Series (Daily)"][day]["1. open"];
      const higher = this.state.data["Time Series (Daily)"][day]["2. high"];

      return (
        <div>
          <h2>Symbol: {symbol}</h2>
          <p>Url: {url}</p>
          <ul>
            <li>
              Open price: {open}
            </li>
            <li>
              Higher price: {higher}
            </li>
          </ul>
        </div>
      );
    }
  }

ne sont pas immédiatement observables lors de l'appel suivant à this.setValues ​​(); (qui lui-même dépend de l'objet data défini dans l'état du composant). La solution pour ces situations est d'utiliser le deuxième argument de rappel sur la méthode setState () pour exécuter une logique qui dépend du changement d'état correspondant:

/* The state change will be observable when setValues() is called via
the callback */
this.setState({data: data, loading: false }, () => {

    this.setValues();    
});

En guise de suggestion pour l'implémentation de votre composant, envisagez de réviser la méthode render () afin que day , open et plus haut sont accédés et rendus dans render () directement, plutôt que de mettre en cache ces valeurs ailleurs comme vous semblez le faire. Alors essayez quelque chose comme ceci:

this.setState({data: data, loading: false });


2 commentaires

J'ai modifié le rendu de la fonction comme vous l'avez dit, mais il s'est écrasé de la même manière :(


pouvez-vous inclure une copie de la réponse json renvoyée par votre requête fetch () ?



1
votes

J'ai trouvé une solution:

Il suffit de mettre une instruction if avant return dans le rendu en disant "Le symbole a-t-il changé? Si oui, récupérez, sinon pas"


1 commentaires

Qu'entendez-vous par «Le symbole a-t-il changé»? Quelle méthode / solution avez-vous utilisée? J'ai le même problème dans mon projet.