"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Como construir um React Hook que lide com solicitações sequenciais

Como construir um React Hook que lide com solicitações sequenciais

Publicado em 2024-11-04
Navegar:217

Quando você precisa responder rapidamente às ações do usuário e buscar os dados mais recentes do backend, você pode precisar de um React Hook que suporte solicitações sequenciais. Este gancho pode cancelar solicitações anteriores se ainda estiverem em andamento e retornar apenas os dados mais recentes. Isso não apenas melhora o desempenho, mas também melhora a experiência do usuário.

Construindo um gancho de reação de solicitação sequencial simples

Vamos começar construindo um gancho React de solicitação sequencial simples:

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]);
}

A ideia principal aqui vem do artigo “Como anular promessas em JavaScript”. Você pode usá-lo assim:

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

Dessa forma, ao clicar no botão rapidamente várias vezes, você obterá apenas os dados da última solicitação e as solicitações anteriores serão descartadas.

How to Build a React Hook That Handles Sequential Requests

Construindo um gancho de reação de solicitação sequencial otimizado

Se precisarmos de um React Hook de solicitação sequencial mais abrangente, há espaço para melhorias no código acima. Por exemplo:

  • Podemos adiar a criação de um AbortController até que ele seja realmente necessário, reduzindo custos de criação desnecessários.

  • Podemos usar genéricos para suportar qualquer tipo de argumento de solicitação.

Aqui está a versão atualizada:

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],
  );
}

Observe que no bloco final, verificamos se o controlador atual é igual a abortController.current para evitar condições de corrida. Isso garante que apenas a solicitação ativa possa modificar o estado de execução.

Uso mais abrangente:

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}
> ); }

Você pode experimentar online: conforme você digita rapidamente, as solicitações anteriores serão canceladas e apenas a resposta mais recente será mostrada.

How to Build a React Hook That Handles Sequential Requests


Se você achou isso útil, considere assinar meu boletim informativo para artigos e ferramentas mais úteis sobre desenvolvimento web. Obrigado por ler!

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/zacharylee/how-to-build-a-react-hook-that-handles-sequential-requests-e49?1 Se houver alguma violação, entre em contato com study_golang@163 .com para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3