«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Как создать хук React, который обрабатывает последовательные запросы

Как создать хук React, который обрабатывает последовательные запросы

Опубликовано 4 ноября 2024 г.
Просматривать:894

Когда вам нужно быстро реагировать на действия пользователя и получать последние данные из бэкэнда, вам может потребоваться React Hook, поддерживающий последовательные запросы. Этот хук может отменить предыдущие запросы, если они все еще выполняются, и вернуть только самые последние данные. Это не только повышает производительность, но и упрощает работу пользователя.

Создание простого хука React для последовательного запроса

Давайте начнем с создания простого хука React для последовательного запроса:

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

Ключевая идея здесь взята из статьи «Как аннулировать обещания в JavaScript». Вы можете использовать это так:

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

Таким образом, если вы быстро нажмете кнопку несколько раз, вы получите данные только из последнего запроса, а предыдущие запросы будут отброшены.

How to Build a React Hook That Handles Sequential Requests

Создание оптимизированного React Hook для последовательных запросов

Если нам нужен более полный последовательный запрос React Hook, в приведенном выше коде есть возможности для улучшения. Например:

  • Мы можем отложить создание AbortController до тех пор, пока он действительно не понадобится, сокращая ненужные затраты на создание.

  • Мы можем использовать дженерики для поддержки любого типа аргументов запроса.

Вот обновленная версия:

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

Обратите внимание, что в блоке Final мы проверяем, равен ли текущий контроллер abortController.current, чтобы предотвратить условия гонки. Это гарантирует, что только активный запрос может изменить рабочее состояние.

Более комплексное использование:

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

Вы можете попробовать это онлайн: при быстром наборе текста предыдущие запросы будут отменены, и будет показан только последний ответ.

How to Build a React Hook That Handles Sequential Requests


Если вы нашли это полезным, пожалуйста, рассмотрите возможность подписки на мою рассылку, чтобы получать больше полезных статей и инструментов о веб-разработке. Спасибо за прочтение!

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/zacharylee/how-to-build-a-react-hook-that-handles-sequential-requests-e49?1. Если есть какие-либо нарушения, свяжитесь с Study_golang@163. .com, чтобы удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3