0
votes

Comment gérer les accessoires et l'état asynchrones

Je n'arrive pas à comprendre cela.

Je dois transmettre des données récupérées de manière asynchrone. Le problème est que les accessoires sont également asynchrones. Voici une version simplifiée du composant:

import React, { Component }  from 'react'
import CSVLink from 'react-csv'
import generateData from './customApi/generateData

type Props = { job?: JobType | undefined }
type State = { csvData: string[][] }

class MyComponent extends Component<Props, State> {
  state = {
    csvData = [],
  }

  generateCsv = async (jobId: string) => {
    const csvData = await generateData(jobId)
    this.setState({ csvData })
  }

  async componentDidMount() {
    const { job } = this.props
    await this.generateCsv(job.id)
  }

  render() {
    const { csvData } = this.state

    return (
       <CSVLink data={csvData}>
          <p>Download csv</p>
       </CSVLink>
    )
  }
}

export default connectFirestore(
   (db, params) => ({ getJob(db, params.id) })
)

Fondamentalement, mes accessoires sont récupérés à partir d'un appel d'API à Firestore, donc le chargement du travail prend un certain temps. Le problème est que lorsque j'essaie de passer le jobId dans le async componentDidMount () , il finit par passer undefined , car le Les accessoires de travail ne sont pas encore chargés.

Je ne lie pas tout l'état de passage aux appels asynchrones en cours, mais je ne vois aucun autrement, comment je passerais le csvData de l'appel asynchrone generateDate () une fois que la Promise est résolue.

Je suppose que la façon la plus simple d'aborder cela serait de vérifier d'une manière ou d'une autre si les accessoires à l'intérieur de componentDidMount () sont déjà récupérés?

Quoi serait la bonne façon d'aborder cela?


0 commentaires

4 Réponses :


0
votes

Il vous manque pour implémenter le constructeur où les accessoires sont définis

constructor(props){
  super(props);
  this.state = {
     csvData = [],
  };
}

componentDidMount(){
  //This will work
  console.log(this.props.job);
};


1 commentaires

Bien que je sois d'accord que le constructeur ne doit pas être omis, cela laissera toujours props.job comme indéfini sur le rendu initial



0
votes

Si la propriété job doit être asynchrone, faites-la async: plutôt que de passer une valeur qui changera à l'avenir, vous pouvez passer une Promise qui se résout avec l'id, que de changer votre componentDidMount comme suit:

componentDidMount() {
    const id = await this.props.job;
    this.generateCsv(id)
}

J'espère que cela vous aidera.


1 commentaires

Vous ne pourriez pas appeler wait dans un componentDidMount () synchrone, aussi wait this.props.job ne ferait rien puisque ce n'est pas une fonction.



0
votes

Peut-être que vous devriez changer le code à l'intérieur de votre composant parent, j'imagine que vous faites l'appel API là-bas, car vous passez ces données comme accessoires dans ce composant que vous nous montrez.

J'imagine aussi que vous effectuez l'appel d'API avec la commande fetch, qui peut déclencher une méthode .then (() => {}) lorsque l'appel d'API a fini de se charger, après cela, vous pouvez changer l'état de cela composant transportant les données récupérées par l'API et ALORS rendre cet enfant. Quelque chose que j'ai utilisé récemment pour mon projet était de charger à partir de l'API, de mettre à jour l'état et de rendre conditionnellement le composant enfant, ce qui ne saura pas que j'ai effectué un appel API car je transmets des données déjà chargées. Normalement, pendant qu'il attend, je mets quelque chose comme ceci:

if(this.state.dataFetched == null)
   return(<h1>Loading page...</h1>)
else return <childComponent loadedData = {this.state.dataFetched}/>

Et puis accède à ces données comme this.props.loadedData


0 commentaires

0
votes

Je ne sais pas si c'est la solution optimale, mais cela fonctionne.

J'ai décidé d'utiliser componentDidUpdate () méthode du cycle de vie, où je compare si les accessoires sont déjà mis à jour et une fois qu'ils l'ont fait, j'appelle la fonction asynchrone pour générer le csv data.

async componentDidUpdate(prevProps: Props) {
  if (prevProps !== this.props && !!this.props) {
    const { job } = this.props
    if (job) {
      await this.generateCsv(job.id)
    }
  }
}

De cette façon, nous générons de nouvelles données chaque fois que les données à l'intérieur de props.job ont changé et nous n'essayons pas d'appeler generateCsv () sur undefined alors qu'il est encore en cours de récupération depuis Firestore.


0 commentaires