3 votes

implémenter le hook react useFetch pour travailler dans la fonction submit

J'ai beaucoup d'expérience en matière de réacteurs, mais je suis novice en matière de crochets.
J'ai les éléments suivants useFetch que j'ai modifié après ceci useAsync crochet :

import { useState, useEffect, useCallback } from 'react'

export default function useFetch(url, options, { immediate }) {
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)
  const [isPending, setIsPending] = useState(false)

  const executeFetch = useCallback(async () => {
    setIsPending(true)
    setData(null)
    setError(null)
    await fetch(url, options)
      .then((response) => response.json())
      .then((response) => setData(response))
      .catch((err) => setError(err))
      .finally(() => setIsPending(false))
    return { data, error, isPending }
  }, [url, options, data, error, isPending])

  useEffect(() => {
    if (immediate) {
      executeFetch()
    }
  }, [executeFetch, immediate])
  return { data, error, isPending, executeFetch }
}

Mon problème est que je veux l'utiliser à l'intérieur d'une fonction submit, et les hooks ne fonctionnent pas à l'intérieur d'autres fonctions, comme ceci (version réduite du code pour plus de concision) :

export default function SignupModal({ closeModal }) {
  const { executeFetch } = useFetch(url, {options},
    { immediate: false }
  )

  async function handleSubmit(evt) {
    evt.preventDefault()
    const { data, error, isPending } = await executeFetch()
  }
  ...
}

Actuellement, je lance intentionnellement une erreur dans l'appel, mais la variable d'erreur demeure. null .

Qu'est-ce que je rate ici ? Est-ce que c'est possible avec des crochets ?

Merci d'avance !

7voto

Matt.kaaj Points 2144

Les hooks React ne peuvent être utilisés que dans le corps de votre composant et non dans une autre fonction. executeFetch retourne lui-même { data, error, isPending } et cela en fait un crochet imbriqué, donc vous ne pouvez pas l'utiliser à l'intérieur de votre handleSubmit.

useFetch retourne déjà { data, error, isPending, executeFetch } pour que executeFetch n'ait pas besoin de revenir à nouveau. Vous pouvez accéder à toutes ces données à partir du hook useFetch. Lorsque vous appelez executeFetch data dans votre composant, data, error et isPending seront mis à jour par setState qui fera en sorte que votre hook renvoie un nouvel ensemble de valeurs pour toutes les valeurs mises à jour.

export default function useFetch(url, options, { immediate }) {
  const [data, setData] = useState(null)
  const [error, setError] = useState(null)
  const [isPending, setIsPending] = useState(false)

  const executeFetch = useCallback(async () => {
    setIsPending(true)
    setData(null)
    setError(null)
    await fetch(url, options)
      .then((response) => response.json())
      .then((response) => setData(response))
      .catch((err) => setError(err))
      .finally(() => setIsPending(false))
  }, [url, options, data, error, isPending])

  useEffect(() => {
    if (immediate) {
      executeFetch()
    }
  }, [executeFetch, immediate])
  return { data, error, isPending, executeFetch }
}

export default function SignupModal({ closeModal }) {
  const { executeFetch, data, error, isPending } = useFetch(url, {options},
    { immediate: false }
  )

  async function handleSubmit(evt) {
    evt.preventDefault()
    await executeFetch()
  }    
  ...
  // Example in your return function
  {error != null && <Error />}
  <Button state={isPending ? 'processing' : 'normal'}

}

Mis à jour sur la base du commentaire

Si vous avez besoin d'accéder à des données ou à une erreur dans votre fonction handleSubmit, vous devrez renvoyer la réponse/erreur de la promesse dans votre hook, de sorte que vous devriez pouvoir accéder aux données/erreurs dans votre handleSubmit également.

Je recommande également de passer les options ou toute autre donnée variable susceptible d'être modifiée avant que l'utilisateur ne déclenche handleSubmit à l'executeFetch en tant qu'argument afin que l'executeFetch puisse toujours obtenir les dernières données.

CodeSandBox Exemple 1

CodeSandBox Exemple 2

const useFetch = url => {
  const [error, setError] = useState(null);
  const [isPending, setIsPending] = useState(false);
  const [data, setData] = useState(null);

  const executeFetch = useCallback(
    // Here you will access to the latest updated options. 
    async ({ options }) => {
      setIsPending(true);
      setError(null);
        return await fetch(url, options)
        .then(response => response.json())
        .then(response => {
          setData(response); 
          return response;
        })
        .catch(err => {
          setError(err.message)
          return err;
        })
        .finally(() => setIsPending(false));
    },
    [url, setIsPending, setError]
  );
  return { data, error, isPending, executeFetch }
};

const { data, executeFetch, error, isPending } = useFetch("URL");

  const handleSubmit = useCallback(async (event) => {
    event.preventDefault();
    // I am passing hardcoded { id: 1 } as an argument. This can 
    // be a value from the state ~ user's input depending on your
    // application's logic.
    await executeFetch({ id: 1 }).then(response => {
      // Here you will access to 
      // data or error from promise. 
      console.log('RESPONSE: ', response);
    })
  }, [executeFetch]);

Une autre recommandation est de ne pas passer un booléen pour déclencher executeFetch immédiatement dans votre hook, c'est à l'appelant de décider s'il faut exécuter executeFetch immédiatement ou non.

const { executeFetch, ... } = useFetch(....);
// you can call it immediately after setting the hook if you ever needed
await executeFetch()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X