web-dev-qa-db-fra.com

Réagir Crochets - Faire une demande Ajax

Je viens de commencer à jouer avec les crochets React et je me demande à quoi devrait ressembler une demande AJAX?

J'ai essayé plusieurs fois, mais je ne parviens pas à le faire fonctionner et je ne connais pas vraiment le meilleur moyen de le mettre en œuvre. Ci-dessous ma dernière tentative:

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

const App = () => {
    const URL = 'http://api.com';
    const [data, setData] = useState({});

    useEffect(() => {
        const resp = fetch(URL).then(res => {
          console.log(res)
        });
    });

    return (
        <div>
          // display content here
        </div>
    )
}
5
peter flanagan

Vous pouvez créer un hook personnalisé appelé useFetch qui implémentera le hook useEffect

En passant un tableau vide en tant que deuxième argument au crochet useEffect, la requête sera déclenchée sur componentDidMount.

Voici une démo en code sandbox .

Voir le code ci-dessous.

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

const useFetch = (url) => {
  const [data, updateData] = useState(undefined);

  // empty array as second argument equivalent to componentDidMount
  useEffect(() => {
     fetch(url).then(res => {
        return res.json();
      }).then(json => {
        updateData(json);
     });
  }, []);

  return data;
};

const App = () => {
    const URL = 'http://www.example.json';
    const result = useFetch(URL);

    return (
      <div>
        {JSON.stringify(result)}
      </div>
    );
}
14
Paul Fitzgerald

Excellentes réponses jusqu'à présent, mais je vais ajouter un crochet personnalisé pour le moment où vous souhaitez déclencher une demande, car vous pouvez également le faire.

function useTriggerableEndpoint(fn) {
  const [res, setRes] = useState({ data: null, error: null, loading: null });
  const [req, setReq] = useState();

  useEffect(
    async () => {
      if (!req) return;
      try {
        setRes({ data: null, error: null, loading: true });
        const { data } = await axios(req);
        setRes({ data, error: null, loading: false });
      } catch (error) {
        setRes({ data: null, error, loading: false });
      }
    },
    [req]
  );

  return [res, (...args) => setReq(fn(...args))];
}

Vous pouvez créer une fonction à l'aide de ce crochet pour une méthode d'API spécifique, mais sachez que cette abstraction n'est pas strictement requise et peut être assez dangereuse est utilisé en dehors du contexte d'une fonction de composant React).

const todosApi = "https://jsonplaceholder.typicode.com/todos";

function postTodoEndpoint() {
  return useTriggerableEndpoint(data => ({
    url: todosApi,
    method: "POST",
    data
  }));
}

Enfin, à partir de votre composant de fonction

const [newTodo, postNewTodo] = postTodoEndpoint();

function createTodo(title, body, userId) {
  postNewTodo({
    title,
    body,
    userId
  });
}

Et puis pointez simplement createTodo sur un gestionnaire onSubmit ou onClick. newTodo aura vos statuts de données, de chargement et d'erreur. Code Sandbox ici.

5
horyd

Fonctionne très bien ... Voilà:

EDIT: mis à jour en fonction du changement de version (merci à @mgol de l'avoir signalé à Mon attention dans les commentaires ...

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

const useFetch = url => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  const fetchUser = async () => {
    const response = await fetch(url);
    const data = await response.json();
    const [user] = data.results;
    setData(user);
    setLoading(false);
  };

  useEffect(() => {
    fetchUser();
  }, []);

  return { data, loading };
};

const App = () => {
  const { data, loading } = useFetch('https://api.randomuser.me/');

  return (
    <div className="App">
      {loading ? (
        <div>Loading...</div>
      ) : (
        <React.Fragment>
          <div className="name">
            {data.name.first} {data.name.last}
          </div>
          <img className="cropper" src={data.picture.large} alt="avatar" />
        </React.Fragment>
      )}
    </div>
  );
};

Démo en direct:

 Edit x908rkw8yq

3
SakoBu

En règle générale, vous écriviez l'appel Ajax dans le cycle de vie des composants de la classe componentDidMount et utilisiez setState pour afficher les données renvoyées lorsque la demande a été renvoyée. 

Avec les points d'ancrage, vous utiliseriez useEffect et passeriez un tableau vide en second argument pour que le rappel soit exécuté une fois lors du montage du composant. 

Voici un exemple qui extrait un profil d'utilisateur aléatoire à partir d'une API et en rend le nom. 

function AjaxExample() {
  const [user, setUser] = React.useState(null);
  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        setUser(data.results[0]);
      });
  }, []); // Pass empty array to only run once on mount.
  
  return <div>
    {user ? user.name.first : 'Loading...'}
  </div>;
}

ReactDOM.render(<AjaxExample/>, document.getElementById('app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

0
Yangshun Tay

Je trouve beaucoup d'usages erronés de useEffect dans les réponses ci-dessus.

Une fonction async ne doit pas être passée dans useEffect.

Voyons la signature de useEffect:

useEffect(didUpdate, inputs);

Vous pouvez utiliser des effets secondaires dans la fonction didUpdate et renvoyer une fonction de disposition. La fonction de disposition est très importante, vous pouvez l’utiliser pour annuler une demande, effacer une minuterie, etc.

Toute fonction asynchrone renverra une promesse, mais pas une fonction. Par conséquent, la fonction Disposer n’a aucun effet.

Donc, passer dans une fonction asynchrone peut absolument gérer vos effets secondaires, mais est un anti-modèle de l'API Hooks.

0
李元秋

Je vous recommande d'utiliser react-request-hook car il couvre de nombreux cas d'utilisation (requêtes multiples en même temps, requêtes annulables sur les états de démontage et de demandes gérées). Il est écrit en TypeScript. Vous pourrez donc en tirer parti si votre projet utilise également TypeScript. Sinon, en fonction de votre IDE, vous pourriez voir les indications de type et la bibliothèque fournit également des aides pour vous permettre de saisir en toute sécurité la charge utile attendue à la suite d'une demande.

C'est bien testé (couverture de code à 100%) et vous pouvez l'utiliser aussi simple que cela:

function UserProfile(props) {
  const [user, getUser] = useResource((id) => {
    url: `/user/${id}`,
    method: 'GET'
  })

  useEffect(() => getUser(props.userId), []);

  if (user.isLoading) return <Spinner />;
  return (
    <User 
      name={user.data.name}
      age={user.data.age}
      email={user.data.email}
    >  
  )
}

exemple d'image

Clause de non-responsabilité de l'auteur: Nous utilisons cette implémentation en production. Il y a toute une série de crochets pour tenir les promesses, mais il y a aussi des cas Edge qui ne sont pas couverts ou dont le test est insuffisamment mis en œuvre. react-request-hook est testé avant sa sortie officielle. Son objectif principal est d'être bien testé et sûr à utiliser, car nous avons affaire à l'un des aspects les plus critiques de nos applications.

0
Matheus Schettino

Voici quelque chose qui, je pense, fonctionnera:

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

const App = () => {
    const URL = 'http://api.com';
    const [data, setData] = useState({})

    useEffect(async () => {
      const resp = await fetch(URL);
      const data = await resp.json();

      setData(data);
    }, []);

    return (
      <div>
        { data.something ? data.something : 'still loading' }
      </div>
    )
}

Il y a quelques bits importants:

  • La fonction que vous transmettez à useEffect agit comme une componentDidMount, ce qui signifie qu'elle peut être exécutée plusieurs fois. C'est pourquoi nous ajoutons un tableau vide comme second argument, ce qui signifie "Cet effet n'a pas de dépendances, alors ne l'exécutez qu'une fois".
  • Votre composant App restitue quelque chose même si les données ne sont pas encore disponibles. Vous devez donc gérer le cas où les données ne sont pas chargées mais le composant est rendu. Soit dit en passant, cela ne change rien. Nous le faisons même maintenant.
0
Krasimir