web-dev-qa-db-fra.com

React hook useEffect et Async / attendre sa propre fonction de récupération de données?

J'ai essayé de créer une fonction pour récupérer les données du serveur, et cela fonctionne. Mais je ne sais pas si c'est la bonne façon?

J'ai créé un composant de fonction pour récupérer les données, en utilisant seState, seEffect et Async/Await:

import React, { useState, useEffect } from "react";

const Fetch = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    const fetchData = async () => {
      let res = await fetch(
        "https://api.coindesk.com/v1/bpi/currentprice.json" //example and simple data
      );
      let response = await res.json();
      setData(response.disclaimer); // parse json
      console.log(response);
    };
    fetchData();
  }, []);
  return <div>{data}</div>;
};

export default Fetch; // don't run code snippet, not working, this component must be imported in main

Où je ne suis pas sûr est un endroit à appel la fonction fetchData. Je fais ça à l'intérieur useEffect? Bon endroit? Et, cet appel ne se produira qu'un seul? Parce que j'utilise []?

En général, comment feriez-vous quelque chose comme ça?

3
Milosh N.

Dans l'ensemble, vous vous dirigez dans la bonne direction. Pour récupérer des données, vous voudriez utiliser useEffect et passer [] comme second argument pour s'assurer qu'il ne se déclenche qu'au montage initial.

Je pense que vous pourriez bénéficier du découplage de la fonction fetchJson et de la rendre plus générique, en tant que telle:

const fetchJson = async (url) => {
  const response = await fetch(url);
  return response.json();
};

const Fetch = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetchJson("https://api.coindesk.com/v1/bpi/currentprice.json")
      .then(({ disclaimer }) => setData(disclaimer));
  }, []);

  return <div>{data}</div>;
};
3
Pavel Ye

Une autre option consiste à utiliser une fonction auto-invoquante:

const Fetch = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    (async () => {
      let res = await fetch(
        "https://api.coindesk.com/v1/bpi/currentprice.json" //example and simple data
      );
      let response = await res.json();
      setData(response);
    })();
  }, []);
  return <div>{data}</div>;
};

La suggestion de séparer la logique d'extraction en une fonction distincte est une bonne idée et peut être effectuée comme suit:

const Fetch = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    (async () => {
      let response= await fetchData("https://api.coindesk.com/v1/bpi/currentprice.json");
      setData(response);
    })();
  }, []);
  return <div>{data}</div>;
};

const fetchData = async (url) => {
  const response = await fetch(url);
  const json = await response.json();

  return json;
};

Et encore une autre option consiste à créer une fonction wrapper autour de useEffect qui déclenche pour vous la fonction asynchrone de la même manière:

export function useAsyncEffect(effect: () => Promise<any>) {
  useEffect(() => {
    effect().catch(e => console.warn("useAsyncEffect error", e));
  });
}
1