"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Comment créer un hook React qui gère les requêtes séquentielles

Comment créer un hook React qui gère les requêtes séquentielles

Publié le 2024-11-04
Parcourir:188

Lorsque vous devez répondre rapidement aux actions de l'utilisateur et récupérer les dernières données du backend, vous aurez peut-être besoin d'un React Hook prenant en charge les requêtes séquentielles. Ce hook peut annuler les demandes précédentes si elles sont toujours en cours et renvoyer uniquement les données les plus récentes. Cela améliore non seulement les performances, mais améliore également l'expérience utilisateur.

Création d'un hook de réaction de requête séquentielle simple

Commençons par créer un hook React de requête séquentielle simple :

import { useCallback, useRef } from 'react';
​
const buildCancelableFetch = (
  requestFn: (signal: AbortSignal) => Promise,
) => {
  const abortController = new AbortController();
​
  return {
    run: () =>
      new Promise((resolve, reject) => {
        if (abortController.signal.aborted) {
          reject(new Error('CanceledError'));
          return;
        }
​
        requestFn(abortController.signal).then(resolve, reject);
      }),
​
    cancel: () => {
      abortController.abort();
    },
  };
};
​
function useLatest(value: T) {
  const ref = useRef(value);
  ref.current = value;
  return ref;
}
​
export function useSequentialRequest(
  requestFn: (signal: AbortSignal) => Promise,
) {
  const requestFnRef = useLatest(requestFn);
  const currentRequest = useRef void } | null>(null);
​
  return useCallback(async () => {
    if (currentRequest.current) {
      currentRequest.current.cancel();
    }
​
    const { run, cancel } = buildCancelableFetch(requestFnRef.current);
    currentRequest.current = { cancel };
​
    return run().finally(() => {
      if (currentRequest.current?.cancel === cancel) {
        currentRequest.current = null;
      }
    });
  }, [requestFnRef]);
}

L'idée clé ici vient de l'article « Comment annuler des promesses en JavaScript ». Vous pouvez l'utiliser comme ceci :

import { useSequentialRequest } from './useSequentialRequest';
​
export function App() {
  const run = useSequentialRequest((signal: AbortSignal) =>
    fetch('http://localhost:5000', { signal }).then((res) => res.text()),
  );
​
  return ;
}

De cette façon, lorsque vous cliquez rapidement plusieurs fois sur le bouton, vous n'obtiendrez que les données de la dernière demande et les demandes précédentes seront ignorées.

How to Build a React Hook That Handles Sequential Requests

Création d'un hook de réaction de requête séquentielle optimisé

Si nous avons besoin d'une requête séquentielle plus complète React Hook, il y a place à amélioration dans le code ci-dessus. Par exemple:

  • Nous pouvons différer la création d'un AbortController jusqu'à ce qu'il soit réellement nécessaire, réduisant ainsi les coûts de création inutiles.

  • Nous pouvons utiliser des génériques pour prendre en charge tout type d'arguments de requête.

Voici la version mise à jour :

import { useCallback, useRef } from 'react';
​
function useLatest(value: T) {
  const ref = useRef(value);
  ref.current = value;
  return ref;
}
​
export function useSequentialRequest(
  requestFn: (signal: AbortSignal, ...args: Args) => Promise,
) {
  const requestFnRef = useLatest(requestFn);
​
  const running = useRef(false);
  const abortController = useRef(null);
​
  return useCallback(
    async (...args: Args) => {
      if (running.current) {
        abortController.current?.abort();
        abortController.current = null;
      }
​
      running.current = true;
​
      const controller = abortController.current ?? new AbortController();
      abortController.current = controller;
​
      return requestFnRef.current(controller.signal, ...args).finally(() => {
        if (controller === abortController.current) {
          running.current = false;
        }
      });
    },
    [requestFnRef],
  );
}

Notez que dans le bloc enfin, nous vérifions si le contrôleur actuel est égal à abortController.current pour éviter les conditions de concurrence. Cela garantit que seule la requête active peut modifier l'état d'exécution.

Utilisation plus complète :

import { useState } from 'react';
import { useSequentialRequest } from './useSequentialRequest';
​
export default function Home() {
  const [data, setData] = useState('');
​
  const run = useSequentialRequest(async (signal: AbortSignal, query: string) =>
    fetch(`/api/hello?query=${query}`, { signal }).then((res) => res.text()),
  );
​
  const handleInput = async (queryStr: string) => {
    try {
      const res = await run(queryStr);
      setData(res);
    } catch {
      // ignore errors
    }
  };
​
  return (
    
       {
          handleInput(e.target.value);
        }}
      />
      
Response Data: {data}
> ); }

Vous pouvez l'essayer en ligne : au fur et à mesure que vous tapez rapidement, les demandes précédentes seront annulées et seule la dernière réponse sera affichée.

How to Build a React Hook That Handles Sequential Requests


Si vous avez trouvé cela utile, veuillez envisager de vous abonner à ma newsletter pour des articles et des outils plus utiles sur le développement Web. Merci d'avoir lu !

Déclaration de sortie Cet article est reproduit sur : https://dev.to/zacharylee/how-to-build-a-react-hook-that-handles-sequential-requests-e49?1 En cas de violation, veuillez contacter study_golang@163 .com pour le supprimer
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3