1
votes

Comment charger des données une seule fois dans une fonction React?

Je récupère les données d'une requête GraphQL, et je souhaite stocker uniquement les 5 premiers éléments dans une variable avant que les filtres ne soient appliqués car j'affiche ces 5 éléments dans un graphique. Chaque fois que je change de page dans la requête pour récupérer plus de données, la variable rankTop est également mise à jour et elle récupère les données de la requête suivante, alors que je souhaite conserver les données que j'ai reçues lors du premier chargement:

export default function DisplayCharts() {
  var [ dataRows, setDataRows ] = useState([]);
  var [ currentPage, setPage ] = useState(0);
  var [ orderCol, setOrderCol ] = useState(null);
  var [ orderColDirection, setOrderColDirection ] = useState(null);
  var [ rowsPerPage, setRowsPerPage] = useState(15);

  const variables = {
      page: currentPage,
      orderCol: orderCol,
      orderDirection: orderColDirection,
      rows_per_page: rowsPerPage
  };

  const { loading, error, data } = useQuery(
    getAllRank,
    {
      variables: variables,
      fetchPolicy: "cache-and-network"
    }
  );

  useEffect(() => {
    if(loading === false && data){
      setDataRows(data.getAllRank.rows);
      setPage(data.getAllRank.page);
    }
  }, [loading, data, currentPage]);

  if (loading) return "Loading...";
  if (error) return `Error! ${error.message}`;
  const rankTop = dataRows.slice(0,5);
  var topFive = [];
  rankTop.map((item, index) => {  //When the data is requested again, this variable takes the new data and I would like to keep the one I got when it first loaded.
    topFive.push ({
      "name": item.name,
      "age": item.age,
      "rank": item.rank
    })
  });

Des suggestions pour y parvenir?

Merci!


5 commentaires

Vous devez diviser vos états en sous-composants, useState doit être utilisé une et une seule fois par composant pour maintenir la cohérence de l'état. J'ai eu des problèmes similaires dans le passé et c'était le coupable.


Donc, vous voulez dire quelque chose comme , et le NewComponent ne rechargera pas les données une fois que actualQuery aura chargé de nouvelles données?


Le but des hooks est de recharger le composant lors du changement d'état. Les nouvelles valeurs dans vos paramètres déclencheront toujours un changement d'état. Ce que je veux dire, c'est qu'en général, vous devez séparer les parties de votre application en sous-composants, de sorte que les changements d'état de ces sous-composants ne déclenchent pas de changement d'état dans l'ensemble de l'application. Cependant, après avoir examiné votre utilisation de useState, il semble que vous puissiez réduire tous ces champs en un seul objet d'état. De plus, vous pourriez provoquer une boucle avec useEffect parce que vous lui dites de se déclencher lorsque 'data' est modifié mais que vous définissez ensuite les données dans useEffect.


Salut @BitShift merci d'avoir pris le temps. Je ne trouve pas de moyen de concevoir le


Hé pas de soucis. Laisse-moi voir si je peux préparer quelque chose ici.


3 Réponses :


0
votes

Vous définissez page: currentPage dans vos variables que vous passez à useQuery mais vous mettez ensuite à jour la currentPage à partir des résultats de la requête dans le useEffect . Ce serait bien si les valeurs sont identiques, mais si les résultats changent cette valeur, la requête sera réexécutée.


0 commentaires

0
votes

Tout d'abord, réduisez votre liste de useStates () à ceci:

var topFive = useRef([])
....
....
topfive.push ....
.... 

Aussi après un examen plus approfondi de votre code: le problème n'est pas qu'il ne doit "charger qu'une fois".

Ce que vous voulez, c'est utiliser l'état précédent et, je suppose, le fusionner avec l'état actuel.

Ce qui se passe est le suivant:

  • votre composant se charge
  • Déclencheurs useEffect
  • vous définissezDataRows
  • le code continue de s'exécuter, dataRows.split est affecté à rankTop
  • La nouvelle page redémarre le processus ci-dessus et vous perdez votre premier 5.

L'avant-dernière et dernière étape est celle où vous perdez les données, pas plus bas pendant l'appel de carte.

Regardez dans useRef () . Vous pouvez également utiliser useCallback () qui est la version du composant de fonction de shouldComponentUpdate ()

Quelques tutoriels sur la façon de l'utiliser peuvent être trouvés ici et here

De plus, la fusion profonde de l'état précédent après un nouveau rendu peut être effectuée avec quelque chose comme:

const prevState = useRef();
....
....
setState({...prevState, <variable1>, <variable2>, etc...});


2 commentaires

Merci @BitShift pour l'explication. Cela a du sens mais je dois utiliser useRef () avant le conditionnel qui vérifie si les données variables ont déjà les données graphql, donc chaque fois que j'essaie d'utiliser useRef avant ce conditionnel, la variable avec les données est vide ... obtenir les données sans utiliser de conditionnel? Merci!


Je viens de remarquer que topFive est en cours d'initialisation à l'intérieur du composant et donc à chaque rendu. Essayez de passer un tableau vide dans useRef () et de l'affecter à topFive



0
votes

Définissez le premier rang uniquement lorsqu'il n'a pas été défini précédemment - ne le calculez pas sur chaque rendu

var [ topRank, setTopRank ] = useState(null);
...
...
useEffect(() => {
  if(loading === false && data){
    if(!topRank) {
      const rankTopData = data.getAllRank.rows.slice(0,5);
      var topFive = [];
      rankTopData.map((item, index) => {  //When the data is requested again, this variable takes the new data and I would like to keep the one I got when it first loaded.
        topFive.push ({
          "name": item.name,
          "age": item.age,
          "rank": item.rank
        })
      });        
      setTopRank(topFive);
    }
    setDataRows(data.getAllRank.rows);
    setPage(data.getAllRank.page);
  }
}, [loading, data, currentPage]);


1 commentaires

À peu près sûr, il doit charger plus de données, puis filtrer et fusionner avec les nouvelles données, pas seulement conserver les anciennes données et les définir une fois. Bien que ce soit une solution brillamment simple!