Maison > interface Web > js tutoriel > le corps du texte

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

WBOY
Libérer: 2024-08-21 09:06:05
original
718 Les gens l'ont consulté

Lorsque vous devez répondre rapidement aux actions des utilisateurs 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 = <T>(
  requestFn: (signal: AbortSignal) => Promise<T>,
) => {
  const abortController = new AbortController();
​
  return {
    run: () =>
      new Promise<T>((resolve, reject) => {
        if (abortController.signal.aborted) {
          reject(new Error('CanceledError'));
          return;
        }
​
        requestFn(abortController.signal).then(resolve, reject);
      }),
​
    cancel: () => {
      abortController.abort();
    },
  };
};
​
function useLatest<T>(value: T) {
  const ref = useRef(value);
  ref.current = value;
  return ref;
}
​
export function useSequentialRequest<T>(
  requestFn: (signal: AbortSignal) => Promise<T>,
) {
  const requestFnRef = useLatest(requestFn);
  const currentRequest = useRef<{ cancel: () => 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]);
}
Copier après la connexion

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 <button onClick={run}>Run</button>;
}
Copier après la connexion

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 rejeté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<T>(value: T) {
  const ref = useRef(value);
  ref.current = value;
  return ref;
}
​
export function useSequentialRequest<Args extends unknown[], Data>(
  requestFn: (signal: AbortSignal, ...args: Args) => Promise<Data>,
) {
  const requestFnRef = useLatest(requestFn);
​
  const running = useRef(false);
  const abortController = useRef<AbortController | null>(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],
  );
}
Copier après la connexion

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 (
    <>
      <input
        placeholder="Please input"
        onChange={(e) => {
          handleInput(e.target.value);
        }}
      />
      <div>Response Data: {data}</div>
    </>
  );
}
Copier après la connexion

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 !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal